Index: generic/tclInt.h ================================================================== --- generic/tclInt.h +++ generic/tclInt.h @@ -850,10 +850,12 @@ ? ((TclVarHashTable *) ((((VarInHash *) (varPtr))->entry.tablePtr)))->nsPtr \ : NULL) #define VarHashRefCount(varPtr) \ ((VarInHash *) (varPtr))->refCount + +MODULE_SCOPE Var * TclArrayContaining(Var *varPtr); /* * Macros for direct variable access by TEBC. */ Index: generic/tclOOBasic.c ================================================================== --- generic/tclOOBasic.c +++ generic/tclOOBasic.c @@ -726,31 +726,18 @@ * Now that we've pinned down what variable we're really talking about * (including traversing variable links), convert back to a name. */ 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); } Tcl_SetObjResult(interp, varNamePtr); return TCL_OK; Index: generic/tclVar.c ================================================================== --- generic/tclVar.c +++ generic/tclVar.c @@ -109,10 +109,17 @@ return VarHashGetValue(hPtr); } else { return NULL; } } + +Var * +TclArrayContaining( + Var *varPtr) +{ + return (Var *) Tcl_GetHashValue( &(((VarInHash *)varPtr)->entry)); +} #define VarHashGetKey(varPtr) \ (((VarInHash *)(varPtr))->entry.key.objPtr) #define VarHashDeleteTable(tablePtr) \ @@ -1070,10 +1077,11 @@ if (isNew) { if (arrayPtr->flags & VAR_SEARCH_ACTIVE) { DeleteSearches((Interp *) interp, arrayPtr); } TclSetVarArrayElement(varPtr); + Tcl_SetHashValue( &(((VarInHash *)varPtr)->entry), arrayPtr); } } else { varPtr = VarHashFindVar(arrayPtr->value.tablePtr, elNamePtr); if (varPtr == NULL) { if (flags & TCL_LEAVE_ERR_MSG) { @@ -2485,11 +2493,17 @@ Tcl_Obj *part2Ptr, int flags, 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)) { DeleteSearches(iPtr, arrayPtr); } else if (varPtr->flags & VAR_SEARCH_ACTIVE) { Index: tests/var.test ================================================================== --- tests/var.test +++ tests/var.test @@ -1200,10 +1200,31 @@ array set $vn {a 1 b 2 c 3} array for $vn $vn {} } -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} catch {unset v}