Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
[PATCH] Remove support for named references to subscripted variables
- X-seq: zsh-workers 54198
- From: Philippe Altherr <philippe.altherr@xxxxxxxxx>
- To: Zsh hackers list <zsh-workers@xxxxxxx>
- Subject: [PATCH] Remove support for named references to subscripted variables
- Date: Wed, 18 Feb 2026 20:37:12 +0100
- Arc-authentication-results: i=1; mx.google.com; arc=none
- Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=to:subject:message-id:date:from:mime-version:dkim-signature; bh=sJO/9LTF1YbmTprJehnUd7e9t5lx9M8F0EI8pMGJNmU=; fh=BgAYDYpL6Ne/A5nWEMVJiHiBtrz8Imz3uf26RDwgQX4=; b=SYdu2TjnCzyFLX27Dzz0zf9igfjfeKx4fkFoWL7CFG/BslkgxqWDWM48MIebszBeYM mVvUBDOsLEt6150FU89igv0PDQAjdacd7KoOvPOm8ix5kzEFgd2EWn9NwhNSMmTUHi98 HYzgwKDTXwgB2BelQAPHyAABs0VWdkgt70hgzv7y28x0uoa6ZRvv/PLuLMZzQR6TtJcm sd6D8fM0z/TAH+CBSJti2X6cMAdLNz+2tF/W6rIh13n/Ngj3KjpYIKRmtghl1GsHY3pb QWsQOx939LM9DMv6VBLJIj+vX5yDy/xNEIccSw8ZIBteULlReP1DwNpE2mM9bT6CmFh8 T2CA==; darn=zsh.org
- Arc-seal: i=1; a=rsa-sha256; t=1771443446; cv=none; d=google.com; s=arc-20240605; b=EbHB/q5xiZiOQXQtjnqTtqCZPV5R91uPbvAjQGJj02ZOcPihyy2SHY1hQC04715obu 93hQ4q0xNznAf+xB9cvYKaRVzoy7ifVl4JHLabwjj/Zq2KVQhyCaCMDC3Qy2/gCYRxKJ Lm6Vzwl/RvDa9MoaDsruCm6Q382oQcjaoStJKTn5b4mvqO06nv1wU/6N692p9jE7+Csk HoS7AWRqD5yCk1DJGvKVuNKaHmEycWmdI7nNbdOZMktJpFuNAW2PBRxvhS/GXUH7Gmvx guxL19P35A337v58GTKXI/d1QT6ZlhbyvBoRNz3NMysP+JHu4vvY6oGbF7HLqkIkZ8vY n2rg==
- Archived-at: <https://zsh.org/workers/54198>
- List-id: <zsh-workers.zsh.org>
Here is a patch to remove support for named references to subscripted variables. While working on this I discovered a number of new issues. Two of them are addressed in the path:
- For loops don't check the validity of variable names that they assign to named references.
For reviewing the patch, it might be easier to review on GitHub the 6 commits it consists of:
Philippe
diff --git a/Src/builtin.c b/Src/builtin.c
index c269dc1c6..6a855ccbf 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -2041,13 +2041,8 @@ typeset_single(char *cname, char *pname, Param pm, int func,
(on & ~(PM_NAMEREF|PM_LOCAL|PM_READONLY))) {
/* Changing type of PM_SPECIAL|PM_AUTOLOAD is a fatal error. *
* Should this be a fatal error as well, rather than warning? */
- if (pm->width)
- zwarnnam(cname,
- "%s: can't change type via subscript reference",
- pm->u.str);
- else
- zwarnnam(cname, "%s: can't change type of a named reference",
- pname);
+ zwarnnam(cname, "%s: can't change type of a named reference",
+ pname);
return NULL;
}
}
@@ -3915,8 +3910,7 @@ bin_unset(char *name, char **argv, Options ops, int func)
zerrnam(name, "%s: restricted", pm->node.nam);
returnval = 1;
} else if (ss) {
- if ((pm->node.flags & PM_NAMEREF) &&
- (!(pm = resolve_nameref(pm)) || pm->width)) {
+ if ((pm->node.flags & PM_NAMEREF) && !(pm = resolve_nameref(pm))) {
/* warning? */
continue;
}
diff --git a/Src/params.c b/Src/params.c
index 3199fd17b..2a6f16a04 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -2206,7 +2206,6 @@ fetchvalue(Value v, char **pptr, int bracks, int scanflags)
} else {
Param pm;
int isvarat;
- int isrefslice = 0;
isvarat = (t[0] == '@' && !t[1]);
if (scanflags & SCANPM_NONAMEREF)
@@ -2224,32 +2223,6 @@ fetchvalue(Value v, char **pptr, int bracks, int scanflags)
if (!pm || ((pm->node.flags & PM_UNSET) &&
!(pm->node.flags & PM_DECLARED)))
return NULL;
- if ((pm->node.flags & PM_NAMEREF) && !(scanflags & SCANPM_NONAMEREF)) {
- char *refname = GETREFNAME(pm);
- if (refname && *refname) {
- /* only happens for namerefs pointing to array elements */
- char *ref = dupstring(refname);
- char *ss = pm->width ? ref + pm->width : NULL;
- if (ss) {
- sav = *ss;
- *ss = 0;
- }
- Param p1 = (Param)gethashnode2(paramtab, ref);
- if (p1)
- pm = loadparamnode(paramtab, upscope(p1, pm), ref);
- if (!(p1 && pm) ||
- ((pm->node.flags & PM_UNSET) &&
- !(pm->node.flags & PM_DECLARED)))
- return NULL;
- if (ss) {
- scanflags |= SCANPM_NOEXEC;
- *ss = sav;
- s = dyncat(ss,*pptr);
- isrefslice = 1;
- } else
- s = *pptr;
- }
- }
if (!v)
v = (Value) zhalloc(sizeof *v);
memset(v, 0, sizeof(*v));
@@ -2263,8 +2236,6 @@ fetchvalue(Value v, char **pptr, int bracks, int scanflags)
v->scanflags = SCANPM_ARRONLY;
}
v->pm = pm;
- if (isrefslice)
- v->valflags = VALFLAG_REFSLICE;
v->end = -1;
if (bracks > 0 && (*s == '[' || *s == Inbrack)) {
if (getindex(&s, v, scanflags)) {
@@ -3228,7 +3199,6 @@ assignsparam(char *s, char *val, int flags)
createparam(t, PM_SCALAR);
created = 1;
} else if ((((v->pm->node.flags & PM_ARRAY) &&
- !(v->valflags & VALFLAG_REFSLICE) &&
!(flags & ASSPM_AUGMENT)) ||
(v->pm->node.flags & PM_HASHED)) &&
!(v->pm->node.flags & (PM_SPECIAL|PM_TIED)) &&
@@ -3387,7 +3357,6 @@ assignaparam(char *s, char **val, int flags)
createparam(t, PM_ARRAY);
created = 1;
} else if (!(PM_TYPE(v->pm->node.flags) & (PM_ARRAY|PM_HASHED)) &&
- !(v->valflags & VALFLAG_REFSLICE) &&
!(v->pm->node.flags & (PM_SPECIAL|PM_TIED))) {
int uniq = v->pm->node.flags & PM_UNIQUE;
if ((flags & ASSPM_AUGMENT) && !(v->pm->node.flags & PM_UNSET)) {
@@ -3614,8 +3583,7 @@ sethparam(char *s, char **val)
if (!(v = fetchvalue(&vbuf, &s, 1, SCANPM_ASSIGNING))) {
createparam(t, PM_HASHED);
checkcreate = 1;
- } else if (!(PM_TYPE(v->pm->node.flags) & PM_HASHED) &&
- !(v->valflags & VALFLAG_REFSLICE)) {
+ } else if (!(PM_TYPE(v->pm->node.flags) & PM_HASHED)) {
if (!(v->pm->node.flags & PM_SPECIAL)) {
if (resetparam(v->pm, PM_HASHED)) {
unqueue_signals();
@@ -6332,9 +6300,7 @@ resolve_nameref_rec(Param pm, const Param stop, int keep_lastref)
pm->node.flags &= ~PM_UNSET;
return pm;
}
- /* pm->width is the offset of any subscript */
- /* If present, it has to be the end of any chain, see fetchvalue() */
- if (refname && *refname && !pm->width) {
+ if (refname && *refname) {
queue_signals();
if ((hn = (Param)gethashnode2(realparamtab, refname))) {
if ((hn = loadparamnode(paramtab, upscope(hn, pm), refname)) &&
@@ -6364,7 +6330,11 @@ setloopvar(char *name, char *value)
zerr("read-only reference: %s", pm->node.nam);
return;
}
- pm->base = pm->width = 0;
+ if (!valid_refname(value, pm->node.flags)) {
+ zerr("invalid name reference: %s", value);
+ return;
+ }
+ pm->base = 0;
SETREFNAME(pm, ztrdup(value));
pm->node.flags &= ~PM_UNSET;
setscope(pm);
@@ -6380,21 +6350,8 @@ setscope(Param pm)
if (pm->node.flags & PM_NAMEREF) {
Param basepm = NULL;
char *refname = GETREFNAME(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;
- 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)) &&
@@ -6413,7 +6370,7 @@ setscope(Param pm)
}
/* Check for self references */
- if (refname && *refname && !pm->width && basepm != pm) {
+ if (refname && *refname && basepm != pm) {
dont_queue_signals(); /* Prevent unkillable loops */
basepm = resolve_nameref_rec(pm, pm, 0);
restore_queue_signals(q);
@@ -6441,47 +6398,14 @@ upscope(Param pm, const Param ref)
static int
valid_refname(char *val, int flags)
{
- char *t;
-
if (flags & PM_UPPER) {
/* Upward reference to positionals is doomed to fail */
- if (idigit(*val))
- return 0;
- t = itype_end(val, INAMESPC, 0);
- if ((t - val == 4) &&
- (!strncmp(val, "argv", 4) ||
- !strncmp(val, "ARGC", 4)))
- return 0;
- } else if (idigit(*val)) {
- t = val;
- while (*++t)
- if (!idigit(*t))
- break;
- if (*t && *t != '[') /* Need to test Inbrack here too? */
- return 0;
- } else
- t = itype_end(val, INAMESPC, 0);
-
- if (t == val) {
- if (!(*t == '!' || *t == '?' ||
- *t == '$' || *t == '-' ||
- *t == '_'))
+ if (idigit(*val) || !strcmp(val, "argv") || !strcmp(val, "ARGC"))
return 0;
- ++t;
}
- if (*t == '[') {
- /* Another bit of isident() to emulate */
- tokenize(t = dupstring(t+1));
- while ((t = parse_subscript(t, 0, ']')) && *t++ == Outbrack) {
- if (*t == Inbrack)
- ++t;
- else
- break;
- }
- if (t && *t) {
- /* zwarn("%s: stuff after subscript: %s", val, t); */
- return 0;
- }
- }
- return !!t;
+
+ if (*val == '!' || *val == '?' || *val == '$' || *val == '-')
+ return !*(++val);
+
+ return !*itype_end(val, INAMESPC, 0) && isident(val);
}
diff --git a/Src/zsh.h b/Src/zsh.h
index 0dc83ded4..0c47f5ef0 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -758,7 +758,6 @@ enum {
VALFLAG_INV = 0x0001, /* We are performing inverse subscripting */
VALFLAG_EMPTY = 0x0002, /* Subscripted range is empty */
VALFLAG_SUBST = 0x0004, /* Substitution, so apply padding, case flags */
- VALFLAG_REFSLICE= 0x0008 /* Value is a reference to an array slice */
};
#define MAX_ARRLEN 262144
diff --git a/Test/K01nameref.ztst b/Test/K01nameref.ztst
index e0f7b1879..801378703 100644
--- a/Test/K01nameref.ztst
+++ b/Test/K01nameref.ztst
@@ -33,44 +33,44 @@
}
function g() {
- if (($2)); then local -n $1 rs ra rs1 ra1;
- else local -n $1 rs=s ra=a rs1="s[1]" ra1="a[1]"; fi;
- if (($2 == 1)); then rs=s; ra=a; rs1="s[1]"; ra1="a[1]"; fi;
- echo "$0:1: rs=$rs - ra=$ra - rs1=$rs1 - ra1=$ra1";
+ if (($2)); then local -n $1 rs ra;
+ else local -n $1 rs=s ra=a; fi;
+ if (($2 == 1)); then rs=s; ra=a; fi;
+ echo "$0:1: rs=$rs - ra=$ra";
local s=$0 a=($0);
- if (($2 == 2)); then rs=s; ra=a; rs1="s[1]"; ra1="a[1]"; fi;
- echo "$0:2: rs=$rs - ra=$ra - rs1=$rs1 - ra1=$ra1";
+ if (($2 == 2)); then rs=s; ra=a; fi;
+ echo "$0:2: rs=$rs - ra=$ra";
h "$@";
- echo "$0:3: rs=$rs - ra=$ra - rs1=$rs1 - ra1=$ra1";
+ echo "$0:3: rs=$rs - ra=$ra";
}
function h() {
- if (($2 == 3)); then rs=s; ra=a; rs1="s[1]"; ra1="a[1]"; fi;
- echo "$0:1: rs=$rs - ra=$ra - rs1=$rs1 - ra1=$ra1";
+ if (($2 == 3)); then rs=s; ra=a; fi;
+ echo "$0:1: rs=$rs - ra=$ra";
local s=$0 a=($0);
- if (($2 == 4)); then rs=s; ra=a; rs1="s[1]"; ra1="a[1]"; fi;
- echo "$0:2: rs=$rs - ra=$ra - rs1=$rs1 - ra1=$ra1";
+ if (($2 == 4)); then rs=s; ra=a; fi;
+ echo "$0:2: rs=$rs - ra=$ra";
i "$@";
- echo "$0:3: rs=$rs - ra=$ra - rs1=$rs1 - ra1=$ra1";
+ echo "$0:3: rs=$rs - ra=$ra";
# Check that re-entering the same scope doesn't undo scope exit
k "$@"
}
function i() {
- if (($2 == 5)); then rs=s; ra=a; rs1="s[1]"; ra1="a[1]"; fi;
- echo "$0:1: rs=$rs - ra=$ra - rs1=$rs1 - ra1=$ra1";
+ if (($2 == 5)); then rs=s; ra=a; fi;
+ echo "$0:1: rs=$rs - ra=$ra";
local s=$0 a=($0);
- if (($2 == 6)); then rs=s; ra=a; rs1="s[1]"; ra1="a[1]"; fi;
- echo "$0:2: rs=$rs - ra=$ra - rs1=$rs1 - ra1=$ra1";
+ if (($2 == 6)); then rs=s; ra=a; fi;
+ echo "$0:2: rs=$rs - ra=$ra";
j "$@";
- echo "$0:3: rs=$rs - ra=$ra - rs1=$rs1 - ra1=$ra1";
+ echo "$0:3: rs=$rs - ra=$ra";
k "$@";
}
function j() {
- echo "$0:1: rs=$rs - ra=$ra - rs1=$rs1 - ra1=$ra1";
+ echo "$0:1: rs=$rs - ra=$ra";
local s=$0 a=($0);
- echo "$0:2: rs=$rs - ra=$ra - rs1=$rs1 - ra1=$ra1";
+ echo "$0:2: rs=$rs - ra=$ra";
}
functions -c j k
@@ -212,11 +212,6 @@ F:note this causes "var" to become set
>typeset -n ptr=var
>typeset -t var
- typeset -n ptr=var[2]
- typeset -t ptr
-1:change type of referenced array element
-*?*var\[2\]: can't change type via subscript reference
-
typeset -n ptr[1]=var
1:illegal nameref name
*?*reference variable cannot be an array
@@ -224,82 +219,191 @@ F:note this causes "var" to become set
typeset var=value
typeset -n ptr=var
print $ptr
-0:basic nameref expansion, no braces
+ print $ptr[2,4]
+0:nameref expansion, no braces
>value
+>alu
typeset var=value
typeset -n ptr=var
print ${ptr}
-0:basic nameref expansion, braces
+ print ${(U)ptr}
+ print ${ptr[2,5][1,3]}
+ print ${(U)ptr[2,5][1,3]}
+0:nameref expansion, braces
>value
+>VALUE
+>alu
+>ALU
typeset var=(val1 val2)
typeset -n ptr=var
print $ptr
-0:nameref array expansion
+ print $ptr[2]
+0:nameref array expansion, no braces
>val1 val2
+>val2
- typeset -A var=(val1 val2)
+ typeset var=(val1 val2)
typeset -n ptr=var
- print ${(kv)ptr}
-0:nameref hash expansion
+ print ${ptr}
+ print ${(O)ptr}
+ print ${ptr[2]}
+ print ${(U)ptr[2]}
+ print ${ptr[2][2,4]}
+ print ${(U)ptr[2][2,4]}
+0:nameref array expansion, braces
>val1 val2
+>val2 val1
+>val2
+>VAL2
+>al2
+>AL2
+ typeset -A var=(key1 val1 key2 val2)
typeset -n ptr=var
+ print $ptr
+ print $ptr[key2]
+0:nameref hash expansion, no braces
+>val1 val2
+>val2
+
+ typeset -A var=(key1 val1 key2 val2)
+ typeset -n ptr=var
+ print ${ptr}
+ print ${(kv)ptr}
+ print ${ptr[key2]}
+ print ${(U)ptr[key2]}
+ print ${ptr[key2][2,4]}
+ print ${(U)ptr[key2][2,4]}
+0:nameref hash expansion, braces
+>val1 val2
+>key1 val1 key2 val2
+>val2
+>VAL2
+>al2
+>AL2
+
typeset var=value
- typeset -p ptr var
+ typeset -n ptr=var
ptr=newvalue
- typeset -p ptr var
-0:assign existing scalar via nameref
->typeset -n ptr=var
->typeset var=value
->typeset -n ptr=var
+ typeset -p var
+ ptr[3]=xt
+ typeset -p var
+ typeset ptr=newvalue
+ typeset -p var
+ typeset ptr[3]=xt
+ typeset -p var
+0:assign/typeset existing scalar via nameref
+>typeset var=newvalue
+>typeset var=nextvalue
>typeset var=newvalue
+>typeset var=nextvalue
+ typeset var=(val1 val2)
+ typeset -n ptr=var
+ ptr=(new1 new2 new3 new4 new5)
+ typeset -p var
+ ptr[3]=new6
+ typeset -p var
+ ptr[2,4]=(new7 new8)
+ typeset -p var
+ typeset ptr=(new1 new2 new3 new4 new5)
+ typeset -p var
+ typeset ptr[3]=new6
+ typeset -p var
+ typeset ptr[2,4]=(new7 new8)
+ typeset -p var
+0:assign/typeset existing array via nameref
+>typeset -a var=( new1 new2 new3 new4 new5 )
+>typeset -a var=( new1 new2 new6 new4 new5 )
+>typeset -a var=( new1 new7 new8 new5 )
+>typeset -a var=( new1 new2 new3 new4 new5 )
+>typeset -a var=( new1 new2 new6 new4 new5 )
+>typeset -a var=( new1 new7 new8 new5 )
+
+ typeset -A var=(key1 val1)
typeset -n ptr=var
+ ptr=(key2 val2 key3 val3)
+ typeset -p var
+ ptr[key3]=VAL3
+ ptr[key4]=val4
+ typeset -p var
+ typeset ptr=(key2 val2 key3 val3)
+ typeset -p var
+ typeset ptr[key3]=VAL3
+ typeset ptr[key4]=val4
+ typeset -p var
+0:assign/typeset existing array via nameref
+>typeset -A var=( [key2]=val2 [key3]=val3 )
+>typeset -A var=( [key2]=val2 [key3]=VAL3 [key4]=val4 )
+>typeset -A var=( [key2]=val2 [key3]=val3 )
+>typeset -A var=( [key2]=val2 [key3]=VAL3 [key4]=val4 )
+
+ () {
+ unset var
+ typeset -n ptr=var
+ ptr=value
+ typeset -p var
+ unset var
+ typeset ptr=value
+ typeset -p var
+ }
+ typeset -p var
+1:assign/typeset new scalar via nameref
+>typeset -g var=value
+>typeset var=value
+*?*no such variable: var
+
+ () {
+ unset var
+ typeset -n ptr=var
+ ptr=(val1 val2)
+ typeset -p var
+ unset var
+ typeset ptr=(val1 val2)
+ typeset -p var
+ }
+ typeset -p var
+1:assign/typeset new array via nameref
+>typeset -g -a var=( val1 val2 )
+>typeset -a var=( val1 val2 )
+*?*no such variable: var
+
typeset var=value
+ typeset -n ptr=var
+ unset "ptr[3]"
+ typeset -p var
+ unset "ptr[2,3]"
+ typeset -p var
+ unset ptr
+ typeset -p var
+ typeset var=(val1 val2 val3 val4 val5)
+ unset "ptr[3]"
+ typeset -p var
+ unset "ptr[2,4]"
+ typeset -p var
+ unset ptr
+ typeset -p var
+ typeset -A var=(key1 val1 key2 val2)
+ unset "ptr[key2]"
+ typeset -p var
unset ptr
typeset -p var
0:unset via nameref
+>typeset var=vaue
+>typeset var=ve
+>typeset -a var=( val1 val2 '' val4 val5 )
+>typeset -a var=( val1 '' val5 )
+>typeset -A var=( [key1]=val1 )
- typeset -n ptr=var
typeset var=value
+ typeset -n ptr=var
unset -n ptr
typeset -p var ptr
0:unset of the nameref itself
-F:If earlier tests change, might get "no such variable" here
>typeset var=value
- typeset -n ptr=var
- typeset var=value
- typeset -p ptr var
- typeset ptr=newvalue
- typeset -p ptr var
-0:typeset existing scalar via nameref
->typeset -n ptr=var
->typeset var=value
->typeset -n ptr=var
->typeset var=newvalue
-
- typeset -n ptr=var
- ptr=value
- typeset -p var ptr
-0:assign new scalar via nameref
->typeset -g var=value
->typeset -n ptr=var
-
- unset var
- typeset -n ptr=var
- typeset var=(val1 val2)
- typeset -p ptr var
- ptr=(new1 new2)
- typeset -p ptr var
-0:assign existing array via nameref
->typeset -n ptr=var
->typeset -a var=( val1 val2 )
->typeset -n ptr=var
->typeset -a var=( new1 new2 )
-
typeset -p ptr ptr1 ptr2 var
1:check state of paramtab ONE
F:unexpected side-effects of previous tests
@@ -308,13 +412,6 @@ F:unexpected side-effects of previous tests
*?*no such variable: ptr2
*?*no such variable: var
- typeset -n ptr=var
- ptr=(val1 val2)
- typeset -p var ptr
-0:assign new array via nameref
->typeset -g -a var=( val1 val2 )
->typeset -n ptr=var
-
unset var
typeset -n ptr2=var
typeset -n ptr1=ptr2
@@ -476,82 +573,11 @@ F:unexpected side-effects of previous tests
}
0:regression: not a self reference (test 3)
-
- unset -n ptr2
- typeset -n ptr2='path[2]'
- print -r -- $ptr2
-0q:nameref to array element, no braces
->${path[2]}
-
- unset -n ptr2
- typeset -n ptr2='path[2]'
- print -r -- ${ptr2}
-0q:nameref to array element, with braces
->${path[2]}
-
- unset -n ptr1
- typeset -A hash=(x MISS y HIT)
- typeset -n ptr1='hash[y]'
- print -r -- $ptr1
-0:nameref to hash element, no braces
->HIT
-
- unset -n ptr1
- typeset -A hash=(x MISS y HIT)
- typeset -n ptr1='hash[y]'
- print -r -- ${ptr1}
-0:nameref to hash element, with braces
->HIT
-
- unset -n ptr2
- typeset -a ary=(1 2)
- typeset -n ptr2='ary[2]'
- ptr2=TWO
- typeset -p ary
-0:assign array element by nameref
->typeset -a ary=( 1 TWO )
-
- unset -n ptr2
- typeset -n ptr2='ary[2]'
- ptr2=TWO
- typeset -p ary
-0f:create array element by nameref
-F:ksh93 does not implement this either
->typeset -a ary=( '' TWO )
-
- unset -n ptr1
- typeset -A hash=(x MISS y MISS)
- typeset -n ptr1='hash[y]'
- ptr1=HIT
- typeset -p hash
-0:assign to hash element by nameref
->typeset -A hash=( [x]=MISS [y]=HIT )
-
- unset -n ptr1
- typeset -A hash
- typeset -n ptr1='hash[y]'
- ptr1=HIT
- typeset -p hash
-0f:create hash by element nameref
-F:ksh93 does not implement this either
->typeset -A hash=( [y]=HIT )
-
unset -n ptr1
typeset -n ptr1='not[2]good'
1:invalid nameref
*?*invalid name reference: not\[2\]good
- unset -n ptr1
- unset hash
- typeset -A hash
- typeset -n ptr1='hash[y]'
- print ${ptr1::=HIT}
- typeset -p ptr1 hash
-0f:create hash by element substitution
->HIT
->typeset -n ptr1='hash[y]'
->typeset -A hash=( [y]=HIT )
-
unset -n ptr
unset gval
typeset -n ptr=gval
@@ -619,9 +645,9 @@ F:unexpected side-effects of previous tests
typeset -A var=(myself outside)
() {
- typeset -n myself=var[myself]
+ typeset -n myself=var
local -h var
- print -r -- $myself
+ print -r -- $myself[myself]
typeset -p var
}
0:up-reference part 3, hidden global
@@ -736,15 +762,15 @@ F:Same test, should part 5 output look like this?
if zmodload zsh/parameter; then
() {
zmodload -u zsh/parameter
- typeset -n myself=parameters[myself]
+ typeset -n myself=parameters
local -h parameters
- print -r -- $myself
+ print -r -- $myself[myself]
typeset -p parameters
}
else ZTST_skip='Cannot zmodload zsh/parameter, skipping autoload test'
fi
0:up-reference part 9, autoloading with hidden special
->nameref-local-nameref-local
+>nameref-local-association-readonly-hide-hideval-special
>typeset -h parameters
(
@@ -845,15 +871,6 @@ F:Checking for a bug in zmodload that affects later tests
0:named references with (P), as ${(P)nameref}
>value
- ary=( 'bry[1]' 'bry[2]' )
- bry=( lorem ipsum )
- typeset -n ptr='ary[2]'
- print -r -- ${ptr}
- print -r -- ${(P)ptr}
-0:named references with (P), array element to array element
->bry[2]
->ipsum
-
unset -n ref
unset var
typeset -n ref=var
@@ -989,6 +1006,19 @@ F:Checking for a bug in zmodload that affects later tests
>
*?*reference ref*to local variable one
+ typeset -n ref=var
+ {
+ for ref in valid1 inv@lid valid2; do typeset -p ref; done
+ } always { TRY_BLOCK_ERROR=0 }
+ typeset -nr ref=var
+ {
+ for ref in valid3 valid4; do typeset -p ref; done
+ } always { TRY_BLOCK_ERROR=0 }
+1:for-loop variable is a reference, part 5, errors
+>typeset -n ref=valid1
+*?*invalid name reference: inv@lid
+*?*read-only reference: ref
+
unset -n ref
typeset -n ref
() {
@@ -1001,13 +1031,6 @@ F:Checking for a bug in zmodload that affects later tests
>typeset -n ref=inner
*?*reference ref*to local variable inner
- typeset -n ptr='ary[$(echo 2)]'
- typeset -a ary=(one two three)
- print $ptr
-1:attempt deferred command substitution in subscript
-F:runs in `setopt noexec` so $(...) returns nothing
-*?*bad math expression: empty string
-
unset -n ref
typeset -n ref=GLOBAL
() {
@@ -1091,93 +1114,93 @@ F:previously this could create an infinite recursion and crash
e -u 0
0:assignment at different scope than declaration, -u 0
->g:1: rs=f - ra=f - rs1=f - ra1=f
->g:2: rs=f - ra=f - rs1=f - ra1=f
->h:1: rs=f - ra=f - rs1=f - ra1=f
->h:2: rs=f - ra=f - rs1=f - ra1=f
->i:1: rs=f - ra=f - rs1=f - ra1=f
->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
+>g:1: rs=f - ra=f
+>g:2: rs=f - ra=f
+>h:1: rs=f - ra=f
+>h:2: rs=f - ra=f
+>i:1: rs=f - ra=f
+>i:2: rs=f - ra=f
+>j:1: rs=f - ra=f
+>j:2: rs=f - ra=f
+>i:3: rs=f - ra=f
+>k:1: rs=f - ra=f
+>k:2: rs=f - ra=f
+>h:3: rs=f - ra=f
+>k:1: rs=f - ra=f
+>k:2: rs=f - ra=f
+>g:3: rs=f - ra=f
e '' 0
0:assignment at different scope than declaration, '' 0
->g:1: rs=f - ra=f - rs1=f - ra1=f
->g:2: rs=f - ra=f - rs1=f - ra1=f
->h:1: rs=f - ra=f - rs1=f - ra1=f
->h:2: rs=f - ra=f - rs1=f - ra1=f
->i:1: rs=f - ra=f - rs1=f - ra1=f
->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
+>g:1: rs=f - ra=f
+>g:2: rs=f - ra=f
+>h:1: rs=f - ra=f
+>h:2: rs=f - ra=f
+>i:1: rs=f - ra=f
+>i:2: rs=f - ra=f
+>j:1: rs=f - ra=f
+>j:2: rs=f - ra=f
+>i:3: rs=f - ra=f
+>k:1: rs=f - ra=f
+>k:2: rs=f - ra=f
+>h:3: rs=f - ra=f
+>k:1: rs=f - ra=f
+>k:2: rs=f - ra=f
+>g:3: rs=f - ra=f
e -u 2
0:assignment at different scope than declaration, -u 2
->g:1: rs= - ra= - rs1= - ra1=
->g:2: rs=f - ra=f - rs1=f - ra1=f
->h:1: rs=f - ra=f - rs1=f - ra1=f
->h:2: rs=f - ra=f - rs1=f - ra1=f
->i:1: rs=f - ra=f - rs1=f - ra1=f
->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
+>g:1: rs= - ra=
+>g:2: rs=f - ra=f
+>h:1: rs=f - ra=f
+>h:2: rs=f - ra=f
+>i:1: rs=f - ra=f
+>i:2: rs=f - ra=f
+>j:1: rs=f - ra=f
+>j:2: rs=f - ra=f
+>i:3: rs=f - ra=f
+>k:1: rs=f - ra=f
+>k:2: rs=f - ra=f
+>h:3: rs=f - ra=f
+>k:1: rs=f - ra=f
+>k:2: rs=f - ra=f
+>g:3: rs=f - ra=f
e -u 6
0:assignment at different scope than declaration, -u 6
->g:1: rs= - ra= - rs1= - ra1=
->g:2: rs= - ra= - rs1= - ra1=
->h:1: rs= - ra= - rs1= - ra1=
->h:2: rs= - ra= - rs1= - ra1=
->i:1: rs= - ra= - rs1= - ra1=
->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
+>g:1: rs= - ra=
+>g:2: rs= - ra=
+>h:1: rs= - ra=
+>h:2: rs= - ra=
+>i:1: rs= - ra=
+>i:2: rs=f - ra=f
+>j:1: rs=f - ra=f
+>j:2: rs=f - ra=f
+>i:3: rs=f - ra=f
+>k:1: rs=f - ra=f
+>k:2: rs=f - ra=f
+>h:3: rs=f - ra=f
+>k:1: rs=f - ra=f
+>k:2: rs=f - ra=f
+>g:3: rs=f - ra=f
e '' 6
0:assignment at different scope than declaration, '' 6
->g:1: rs= - ra= - rs1= - ra1=
->g:2: rs= - ra= - rs1= - ra1=
->h:1: rs= - ra= - rs1= - ra1=
->h:2: rs= - ra= - rs1= - ra1=
->i:1: rs= - ra= - rs1= - ra1=
->i:2: rs=i - ra=i - rs1=i - ra1=i
->j:1: rs=i - ra=i - rs1=i - ra1=i
->j:2: rs=i - ra=i - rs1=i - ra1=i
->i:3: rs=i - ra=i - rs1=i - ra1=i
->k:1: rs=i - ra=i - rs1=i - ra1=i
->k:2: rs=i - ra=i - rs1=i - ra1=i
->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
+>g:1: rs= - ra=
+>g:2: rs= - ra=
+>h:1: rs= - ra=
+>h:2: rs= - ra=
+>i:1: rs= - ra=
+>i:2: rs=i - ra=i
+>j:1: rs=i - ra=i
+>j:2: rs=i - ra=i
+>i:3: rs=i - ra=i
+>k:1: rs=i - ra=i
+>k:2: rs=i - ra=i
+>h:3: rs=h - ra=h
+>k:1: rs=h - ra=h
+>k:2: rs=h - ra=h
+>g:3: rs=g - ra=g
f1
0:Transitive references with scoping changes
@@ -1194,91 +1217,119 @@ F:previously this could create an infinite recursion and crash
>h2: ref1=f1 ref2=f1 ref3=f1
>f1: ref1=f1 ref2=f1 ref3=f1
-#
-# The following two tests are linked, do not separate
-#
+ check-valid-referent-name() {
+ local -n ref=$1
+ [[ $ref = $2 ]] || echo "Unexpected expansion result: ref=$1, \$ref=$ref != $2"
+ }
+ check-invalid-variable-name() {
+ {
+ local -- $1=value-$1 2>/dev/null
+ echo "Unexpected valid variable name: $1"
+ } always {
+ TRY_BLOCK_ERROR=0
+ }
+ }
+ check-invalid-referent-name() {
+ {
+ local -n -- ref=$1 2>/dev/null
+ echo "Unexpected valid referent name: $1"
+ } always {
+ TRY_BLOCK_ERROR=0
+ }
+ }
+ local name value;
+ # Test valid variable names.
+ for name in \
+ foo foo. foo.bar foo.456 foo.4ar \
+ .foo .foo.bar .foo.456
+ do
+ local $name=value-$name
+ check-valid-referent-name "$name" value-$name
+ check-invalid-referent-name "$name"@
+ check-invalid-referent-name "$name""[1]"
+ done
+ # Test valid builtin variable names
+ for name value in 123 "" \! 0 \? 0 \$ $$ - 569X _ -n; do
+ check-valid-referent-name "$name" $value
+ check-invalid-referent-name "$name"@
+ check-invalid-referent-name "$name""[1]"
+ done
+ # Test invalid variable names.
+ for name in \
+ .foo. .foo.4ar . foo.. \
+ 123. 123.bar 123.456 123.4ar .. .foo.. \
+ .123 .123. .123.bar .123.456 .123.4ar \
+ 1oo 1oo. 1oo.bar 1oo.456 1oo.4ar \
+ .1oo .1oo. .1oo.bar .1oo.456 .1oo.4ar
+ do
+ check-invalid-variable-name "$name"
+ check-invalid-referent-name "$name"
+ check-invalid-referent-name "$name"@
+ check-invalid-referent-name "$name""[1]"
+ done
+ # Any variable name with more than one non-leading '.' is invalid.
+ for name in {,.}{foo,123,1oo}.{bar,456,4ar}.{,baz,789,7az}; do
+ check-invalid-variable-name "$name"
+ check-invalid-referent-name "$name"
+ done
+ unfunction check-valid-referent-name
+ unfunction check-invalid-variable-name
+ unfunction check-invalid-referent-name
+ unset name value
+0:references to invalid variable names
edgelocal() ( local -n x=$1; typeset -p x; print -r $x )
edgeupper() ( local -nu x=$1; typeset -p x; print -r $x )
- for edge in argv ARGC \@ \* \# 0 1 01 \! \? - _
+ for edge in argv ARGC \@ \* \# 0 1 01 \! \? \$ - _
do
edgelocal $edge
- edgelocal "$edge""[1]"
edgeupper $edge
done
-0:references to builtin specials
-F:Subscripting on 1 01 ! ? - should print first character but do not
+ unfunction edgelocal edgeupper
+0q:references to builtin specials
+F:BUG:References to 1, 2, ... are supported but don't work (always expand to "")
>typeset -n x=argv
>argv
->typeset -n x='argv[1]'
->argv[1]
>typeset -n x=ARGC
>1
->typeset -n x='ARGC[1]'
->1
>typeset -n x=0
>edgelocal
->typeset -n x='0[1]'
->e
>typeset -n x=1
>
->typeset -n x='1[1]'
->
>typeset -n x=01
>
->typeset -n x='01[1]'
->
>typeset -n x=!
>0
->typeset -n x='![1]'
->
>typeset -un x=!
>0
>typeset -n x='?'
>0
->typeset -n x='?[1]'
->
>typeset -un x='?'
>0
+>typeset -n x='$'
+>$$
+>typeset -un x='$'
+>$$
>typeset -n x=-
>569X
->typeset -n x='-[1]'
->
>typeset -un x=-
>569X
>typeset -n x=_
>x
->typeset -n x='_[1]'
->x
>typeset -un x=_
>x
?edgeupper: invalid name reference: argv
?edgeupper: invalid name reference: ARGC
?edgelocal: invalid name reference: @
-?edgelocal: invalid name reference: @[1]
?edgeupper: invalid name reference: @
?edgelocal: invalid name reference: *
-?edgelocal: invalid name reference: *[1]
?edgeupper: invalid name reference: *
?edgelocal: invalid name reference: #
-?edgelocal: invalid name reference: #[1]
?edgeupper: invalid name reference: #
?edgeupper: invalid name reference: 0
?edgeupper: invalid name reference: 1
?edgeupper: invalid name reference: 01
- edgelocal \$
- edgelocal '$[1]'
- edgeupper \$
- unfunction edgelocal edgeupper
-0qf:references to $$
-F:$$[1] reference should print the first digit of $$ but prints nothing
->typeset -n x='$'
->$$
->typeset -n x='\$[1]'
->$$[1]
->$$
-
#
# The following tests are run in interactive mode, using PS1 as an
# assignable special with side-effects. This crashed at one time.
@@ -1346,22 +1397,7 @@ F:$$[1] reference should print the first digit of $$ but prints nothing
zmodload -u zsh/random
echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*}
echo v=${ref/<->/integer}
-0:Referring and dereferring an autoload variable loads it (direct)
->z=SRANDOM (zsh/random)
->z=
->v=integer
->z=SRANDOM (zsh/random)
->v=integer
-
- zmodload -u zsh/random
- echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*}
- typeset -n ref=SRANDOM[1,20]
- echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*}
- echo v=${ref/<->/integer}
- zmodload -u zsh/random
- echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*}
- echo v=${ref/<->/integer}
-0:Referring and dereferring an autoload variable loads it (subscript)
+0:Referring and dereferring an autoload variable loads it
>z=SRANDOM (zsh/random)
>z=
>v=integer
@@ -1375,21 +1411,7 @@ F:$$[1] reference should print the first digit of $$ but prints nothing
typeset -h SRANDOM=local-variable
echo v=${ref/<->/integer}
echo NOT REACHED
-1:Dereferring an autoload variable fails to load it if its hidden (direct)
->v=integer
->z=SRANDOM (zsh/random)
-?(eval):6: Can't add module parameter `SRANDOM': local parameter exists
-?(eval):zsh/random:6: error when adding parameter `SRANDOM'
-?(eval):6: autoloading module zsh/random failed to define parameter: SRANDOM
-
- typeset -n ref=SRANDOM[1,20]
- echo v=${ref/<->/integer}
- zmodload -u zsh/random
- echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*}
- typeset -h SRANDOM=local-variable
- echo v=${ref/<->/integer}
- echo NOT REACHED
-1:Dereferring an autoload variable fails to load it if its hidden (subscript)
+1:Dereferring an autoload variable fails to load it if its hidden
>v=integer
>z=SRANDOM (zsh/random)
?(eval):6: Can't add module parameter `SRANDOM': local parameter exists
@@ -1635,10 +1657,6 @@ F:converting from association/array to string should work here too
1:regression: reference loop with same name enclosing variable
?(anon):3: ptr2: invalid self reference
- typeset -n ref=ref[1]
-1:self reference with subscript
-*?*: ref: invalid self reference
-
typeset var=foo
typeset -n ref=var
() {
Messages sorted by:
Reverse Date,
Date,
Thread,
Author