Compare commits

...
4 Commits
Author SHA1 Message Date
dgp 38a14b1f4f merge 8.7 2018-04-26 18:19:42 +00:00
dgp 5e3c1650cb merge 8.7 2018-04-23 13:51:57 +00:00
dgp 6d8afefe93 Add a test for the compiled pathway. 2018-04-22 23:16:29 +00:00
dgp 82bb26a278 Candidate fix for [e87bcf819f]. Makes sure the unset of a scalar variable
linked to an array element terminates searches on that array.
In order to accomplish this, some deep revisions in Var handling were done
and new routine "Var * TclArrayContaining(Var *varPtr)" was created to return
the (Var *) of the array that contains the (Var *) varPtr argument when it
is an array element. Callers must verify the argument.

The only code that was unhappy with these deep revisions was the
varname method of TclOO, but revising it to the new situation was not too
difficult. Arguably the code is better now, if a bit uglier and fragile to
further deep Var tinkering.

Second party review would be a good idea, as well as opinions on whether
a backport to 8.6.* is warranted to fix corresponding bugs in the array
enumeration suite of commands.
2018-04-22 23:09:47 +00:00
4 changed files with 43 additions and 19 deletions
+2
View File
@@ -853,6 +853,8 @@ typedef struct VarInHash {
#define VarHashRefCount(varPtr) \
((VarInHash *) (varPtr))->refCount
MODULE_SCOPE Var * TclArrayContaining(Var *varPtr);
/*
* Macros for direct variable access by TEBC.
*/
+5 -18
View File
@@ -728,27 +728,14 @@ TclOO_Object_VarName(
*/
varNamePtr = Tcl_NewObj();
if (aryVar != NULL) {
Tcl_HashEntry *hPtr;
Tcl_HashSearch search;
if (TclIsVarArrayElement(varPtr)) {
aryVar = TclArrayContaining(varPtr);
Tcl_GetVariableFullName(interp, (Tcl_Var) aryVar, varNamePtr);
/*
* WARNING! This code pokes inside the implementation of hash tables!
*/
hPtr = Tcl_FirstHashEntry((Tcl_HashTable *) aryVar->value.tablePtr,
&search);
while (hPtr != NULL) {
if (varPtr == Tcl_GetHashValue(hPtr)) {
Tcl_AppendToObj(varNamePtr, "(", -1);
Tcl_AppendObjToObj(varNamePtr, hPtr->key.objPtr);
Tcl_AppendToObj(varNamePtr, ")", -1);
break;
}
hPtr = Tcl_NextHashEntry(&search);
}
Tcl_AppendToObj(varNamePtr, "(", -1);
Tcl_AppendObjToObj(varNamePtr, ((VarInHash *)varPtr)->entry.key.objPtr);
Tcl_AppendToObj(varNamePtr, ")", -1);
} else {
Tcl_GetVariableFullName(interp, (Tcl_Var) varPtr, varNamePtr);
}
+15 -1
View File
@@ -112,6 +112,13 @@ VarHashNextVar(
}
}
Var *
TclArrayContaining(
Var *varPtr)
{
return (Var *) Tcl_GetHashValue( &(((VarInHash *)varPtr)->entry));
}
#define VarHashGetKey(varPtr) \
(((VarInHash *)(varPtr))->entry.key.objPtr)
@@ -1072,6 +1079,7 @@ TclLookupArrayElement(
DeleteSearches((Interp *) interp, arrayPtr);
}
TclSetVarArrayElement(varPtr);
Tcl_SetHashValue( &(((VarInHash *)varPtr)->entry), arrayPtr);
}
} else {
varPtr = VarHashFindVar(arrayPtr->value.tablePtr, elNamePtr);
@@ -2487,7 +2495,13 @@ UnsetVarStruct(
int index)
{
Var dummyVar;
int traced = TclIsVarTraced(varPtr)
int traced;
if (arrayPtr == NULL && TclIsVarArrayElement(varPtr)) {
arrayPtr = TclArrayContaining(varPtr);
}
traced = TclIsVarTraced(varPtr)
|| (arrayPtr && (arrayPtr->flags & VAR_TRACED_UNSET));
if (arrayPtr && (arrayPtr->flags & VAR_SEARCH_ACTIVE)) {
+21
View File
@@ -1202,6 +1202,27 @@ test var-23.14 {array for, shared arguments} -setup {
} -cleanup {
unset -nocomplain $vn vn
} -result {}
test var-23.15 {array for, [Bug e87bcf819f]} -setup {
unset -nocomplain a
array set a {m 1 n 2}
upvar 0 a(n) l
set unset unset
} -body {
array for {k v} a {$unset l}
} -cleanup {
unset -nocomplain a
} -returnCodes error -result {array changed during iteration}
test var-23.15.1 {array for, [Bug e87bcf819f]} -setup {
unset -nocomplain a
array set a {m 1 n 2}
upvar 0 a(n) l
} -body {
array for {k v} a {unset l}
} -cleanup {
unset -nocomplain a
} -returnCodes error -result {array changed during iteration}
catch {namespace delete ns}
catch {unset arr}