Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix for [c1a376375e0e6488], imported namespace ensemble command name distorted during deletion trace on the import |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | bug-c1a376375e0e6488 |
Files: | files | file ages | folders |
SHA3-256: |
ebe34426255bef25a9215197d0202984 |
User & Date: | pooryorick 2020-09-01 22:36:41.393 |
Context
2020-09-02
| ||
09:30 | Merge bug-c1a376375e0e6488 check-in: 28aa719436 user: pooryorick tags: core-8-branch | |
2020-09-01
| ||
22:36 | Fix for [c1a376375e0e6488], imported namespace ensemble command name distorted during deletion trace... Closed-Leaf check-in: ebe3442625 user: pooryorick tags: bug-c1a376375e0e6488 | |
10:33 | Merge 8.6 check-in: 2e2f130b01 user: jan.nijtmans tags: core-8-branch | |
Changes
Changes to generic/tclBasic.c.
︙ | ︙ | |||
2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 | if (oldRefPtr != NULL) { cmdPtr->importRefPtr = oldRefPtr; while (oldRefPtr != NULL) { Command *refCmdPtr = oldRefPtr->importedCmdPtr; dataPtr = (ImportedCmdData*)refCmdPtr->objClientData; dataPtr->realCmdPtr = cmdPtr; oldRefPtr = oldRefPtr->nextPtr; } } /* * We just created a command, so in its namespace and all of its parent | > > | 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 | if (oldRefPtr != NULL) { cmdPtr->importRefPtr = oldRefPtr; while (oldRefPtr != NULL) { Command *refCmdPtr = oldRefPtr->importedCmdPtr; dataPtr = (ImportedCmdData*)refCmdPtr->objClientData; cmdPtr->refCount++; TclCleanupCommandMacro(dataPtr->realCmdPtr); dataPtr->realCmdPtr = cmdPtr; oldRefPtr = oldRefPtr->nextPtr; } } /* * We just created a command, so in its namespace and all of its parent |
︙ | ︙ | |||
3370 3371 3372 3373 3374 3375 3376 | char *name; /* * Add the full name of the containing namespace, followed by the "::" * separator, and the command name. */ | | | 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 | char *name; /* * Add the full name of the containing namespace, followed by the "::" * separator, and the command name. */ if ((cmdPtr != NULL) && TclRoutineHasName(cmdPtr)) { if (cmdPtr->nsPtr != NULL) { Tcl_AppendToObj(objPtr, cmdPtr->nsPtr->fullName, -1); if (cmdPtr->nsPtr != iPtr->globalNsPtr) { Tcl_AppendToObj(objPtr, "::", 2); } } if (cmdPtr->hPtr != NULL) { |
︙ | ︙ | |||
3460 3461 3462 3463 3464 3465 3466 | * invoking the deletion callback because there are cases where the * deletion callback needs to invoke the command (e.g. object systems such * as OTcl). However, this means that the callback could try to delete or * rename the command. The deleted flag allows us to detect these cases * and skip nested deletes. */ | | | 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 | * invoking the deletion callback because there are cases where the * deletion callback needs to invoke the command (e.g. object systems such * as OTcl). However, this means that the callback could try to delete or * rename the command. The deleted flag allows us to detect these cases * and skip nested deletes. */ if (cmdPtr->flags & CMD_DYING) { /* * Another deletion is already in progress. Remove the hash table * entry now, but don't invoke a callback or free the command * structure. Take care to only remove the hash entry if it has not * already been removed; otherwise if we manage to hit this function * three times, everything goes up in smoke. [Bug 1220058] */ |
︙ | ︙ | |||
3492 3493 3494 3495 3496 3497 3498 | * We must delete this command, even though both traces and delete procs * may try to avoid this (renaming the command etc). Also traces and * delete procs may try to delete the command themselves. This flag * declares that a delete is in progress and that recursive deletes should * be ignored. */ | | | 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 | * We must delete this command, even though both traces and delete procs * may try to avoid this (renaming the command etc). Also traces and * delete procs may try to delete the command themselves. This flag * declares that a delete is in progress and that recursive deletes should * be ignored. */ cmdPtr->flags |= CMD_DYING; /* * Call trace functions for the command being deleted. Then delete its * traces. */ cmdPtr->nsPtr->refCount++; |
︙ | ︙ | |||
3522 3523 3524 3525 3526 3527 3528 | } tracePtr = nextPtr; } cmdPtr->tracePtr = NULL; } /* | | | 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 | } tracePtr = nextPtr; } cmdPtr->tracePtr = NULL; } /* * The list of commands exported from the namespace might have changed. * However, we do not need to recompute this just yet; next time we need * the info will be soon enough. */ TclInvalidateNsCmdLookup(cmdPtr->nsPtr); TclNsDecrRefCount(cmdPtr->nsPtr); |
︙ | ︙ | |||
3657 3658 3659 3660 3661 3662 3663 | Tcl_InterpState state = NULL; if (cmdPtr->flags & CMD_TRACE_ACTIVE) { /* * While a rename trace is active, we will not process any more rename * traces; while a delete trace is active we will never reach here - * because Tcl_DeleteCommandFromToken checks for the condition | | | 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 | Tcl_InterpState state = NULL; if (cmdPtr->flags & CMD_TRACE_ACTIVE) { /* * While a rename trace is active, we will not process any more rename * traces; while a delete trace is active we will never reach here - * because Tcl_DeleteCommandFromToken checks for the condition * (cmdPtr->flags & CMD_DYING) and returns immediately when a * command deletion is in progress. For all other traces, delete * traces will not be invoked but a call to TraceCommandProc will * ensure that tracePtr->clientData is freed whenever the command * "oldName" is deleted. */ if (cmdPtr->flags & TCL_TRACE_RENAME) { |
︙ | ︙ | |||
5210 5211 5212 5213 5214 5215 5216 | int objc = PTR2INT(data[0]); Tcl_Obj *commandPtr = (Tcl_Obj *)data[1]; Command *cmdPtr = (Command *)data[2]; Tcl_Obj **objv = (Tcl_Obj **)data[3]; int length; const char *command = TclGetStringFromObj(commandPtr, &length); | | | 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 | int objc = PTR2INT(data[0]); Tcl_Obj *commandPtr = (Tcl_Obj *)data[1]; Command *cmdPtr = (Command *)data[2]; Tcl_Obj **objv = (Tcl_Obj **)data[3]; int length; const char *command = TclGetStringFromObj(commandPtr, &length); if (!(cmdPtr->flags & CMD_DYING)) { if (cmdPtr->flags & CMD_HAS_EXEC_TRACES) { traceCode = TclCheckExecutionTraces(interp, command, length, cmdPtr, result, TCL_TRACE_LEAVE_EXEC, objc, objv); } if (iPtr->tracePtr != NULL && traceCode == TCL_OK) { traceCode = TclCheckInterpTraces(interp, command, length, cmdPtr, result, TCL_TRACE_LEAVE_EXEC, objc, objv); |
︙ | ︙ | |||
6456 6457 6458 6459 6460 6461 6462 | * This also preserves any associations between list elements and * location information for such elements. */ /* * Shimmer protection! Always pass an unshared obj. The caller could * incr the refCount of objPtr AFTER calling us! To be completely safe | | | 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470 6471 6472 | * This also preserves any associations between list elements and * location information for such elements. */ /* * Shimmer protection! Always pass an unshared obj. The caller could * incr the refCount of objPtr AFTER calling us! To be completely safe * we always make a copy. The callback takes care of the refCounts for * both listPtr and objPtr. * * TODO: Create a test to demo this need, or eliminate it. * FIXME OPT: preserve just the internal rep? */ Tcl_IncrRefCount(objPtr); |
︙ | ︙ | |||
9509 9510 9511 9512 9513 9514 9515 | return result; } NRE_ASSERT(COR_IS_SUSPENDED(corPtr)); SAVE_CONTEXT(corPtr->running); RESTORE_CONTEXT(corPtr->caller); | | | 9511 9512 9513 9514 9515 9516 9517 9518 9519 9520 9521 9522 9523 9524 9525 | return result; } NRE_ASSERT(COR_IS_SUSPENDED(corPtr)); SAVE_CONTEXT(corPtr->running); RESTORE_CONTEXT(corPtr->caller); if (cmdPtr->flags & CMD_DYING) { /* * The command was deleted while it was running: wind down the * execEnv, this will do the complete cleanup. RewindCoroutine will * restore both the caller's context and interp state. */ return RewindCoroutine(corPtr, result); |
︙ | ︙ | |||
10278 10279 10280 10281 10282 10283 10284 | CoroutineData *corPtr = iPtr->execEnvPtr->corPtr; if (objc != 1) { Tcl_WrongNumArgs(interp, 1, objv, NULL); return TCL_ERROR; } | | | 10280 10281 10282 10283 10284 10285 10286 10287 10288 10289 10290 10291 10292 10293 10294 | CoroutineData *corPtr = iPtr->execEnvPtr->corPtr; if (objc != 1) { Tcl_WrongNumArgs(interp, 1, objv, NULL); return TCL_ERROR; } if (corPtr && !(corPtr->cmdPtr->flags & CMD_DYING)) { Tcl_Obj *namePtr; TclNewObj(namePtr); Tcl_GetCommandFullName(interp, (Tcl_Command) corPtr->cmdPtr, namePtr); Tcl_SetObjResult(interp, namePtr); } return TCL_OK; |
︙ | ︙ |
Changes to generic/tclCompile.c.
︙ | ︙ | |||
1830 1831 1832 1833 1834 1835 1836 | if ((cmdPtr != NULL) && (cmdPtr->flags & CMD_VIA_RESOLVER)) { extraLiteralFlags |= LITERAL_UNSHARED; } bytes = TclGetStringFromObj(cmdObj, &numBytes); cmdLitIdx = TclRegisterLiteral(envPtr, bytes, numBytes, extraLiteralFlags); | | | 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 | if ((cmdPtr != NULL) && (cmdPtr->flags & CMD_VIA_RESOLVER)) { extraLiteralFlags |= LITERAL_UNSHARED; } bytes = TclGetStringFromObj(cmdObj, &numBytes); cmdLitIdx = TclRegisterLiteral(envPtr, bytes, numBytes, extraLiteralFlags); if (cmdPtr && TclRoutineHasName(cmdPtr)) { TclSetCmdNameObj(interp, TclFetchLiteral(envPtr, cmdLitIdx), cmdPtr); } TclEmitPush(cmdLitIdx, envPtr); } void TclCompileInvocation( |
︙ | ︙ |
Changes to generic/tclEnsemble.c.
︙ | ︙ | |||
3157 3158 3159 3160 3161 3162 3163 | goto cleanup; } ensemble = (Tcl_Command) cmdPtr; goto checkNextWord; } /* | | | 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 | goto cleanup; } ensemble = (Tcl_Command) cmdPtr; goto checkNextWord; } /* * Now that the mapping process is done we actually try to compile. * If there is a subcommand compiler and that successfully produces code, * we'll use that. Otherwise, we fall back to generating opcodes to do the * invoke at runtime. */ invokeAnyway = 1; if (TCL_OK == TclAttemptCompileProc(interp, parsePtr, depth, cmdPtr, |
︙ | ︙ | |||
3257 3258 3259 3260 3261 3262 3263 | if (cmdPtr->compileProc == NULL) { return TCL_ERROR; } /* * Advance parsePtr->tokenPtr so that it points at the last subcommand. | | | | | 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 | if (cmdPtr->compileProc == NULL) { return TCL_ERROR; } /* * Advance parsePtr->tokenPtr so that it points at the last subcommand. * This will be wrong but it will not matter, and it will put the * tokens for the arguments in the right place without the need to * allocate a synthetic Tcl_Parse struct or copy tokens around. */ for (i = 0; i < depth - 1; i++) { parsePtr->tokenPtr = TokenAfter(parsePtr->tokenPtr); } parsePtr->numWords -= (depth - 1); |
︙ | ︙ |
Changes to generic/tclExecute.c.
︙ | ︙ | |||
4460 4461 4462 4463 4464 4465 4466 | NEXT_INST_F(1, 0, 1); } break; case INST_COROUTINE_NAME: { CoroutineData *corPtr = iPtr->execEnvPtr->corPtr; TclNewObj(objResultPtr); | | | 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 | NEXT_INST_F(1, 0, 1); } break; case INST_COROUTINE_NAME: { CoroutineData *corPtr = iPtr->execEnvPtr->corPtr; TclNewObj(objResultPtr); if (corPtr && !(corPtr->cmdPtr->flags & CMD_DYING)) { Tcl_GetCommandFullName(interp, (Tcl_Command) corPtr->cmdPtr, objResultPtr); } TRACE_WITH_OBJ(("=> "), objResultPtr); NEXT_INST_F(1, 0, 1); } break; |
︙ | ︙ | |||
4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 | TRACE_WITH_OBJ(("\"%.20s\" => ", O2S(OBJ_AT_TOS)), objResultPtr); NEXT_INST_F(1, 1, 1); case INST_ORIGIN_COMMAND: TRACE(("\"%.30s\" => ", O2S(OBJ_AT_TOS))); cmd = Tcl_GetCommandFromObj(interp, OBJ_AT_TOS); if (cmd == NULL) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "invalid command name \"%s\"", TclGetString(OBJ_AT_TOS))); DECACHE_STACK_INFO(); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "COMMAND", TclGetString(OBJ_AT_TOS), NULL); CACHE_STACK_INFO(); TRACE_APPEND(("ERROR: not command\n")); goto gotError; } | > > > > > > > > > > > > < < < < < < | 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 | TRACE_WITH_OBJ(("\"%.20s\" => ", O2S(OBJ_AT_TOS)), objResultPtr); NEXT_INST_F(1, 1, 1); case INST_ORIGIN_COMMAND: TRACE(("\"%.30s\" => ", O2S(OBJ_AT_TOS))); cmd = Tcl_GetCommandFromObj(interp, OBJ_AT_TOS); if (cmd == NULL) { goto instOriginError; } origCmd = TclGetOriginalCommand(cmd); if (origCmd == NULL) { origCmd = cmd; } TclNewObj(objResultPtr); Tcl_GetCommandFullName(interp, origCmd, objResultPtr); if (TclCheckEmptyString(objResultPtr) == TCL_EMPTYSTRING_YES ) { Tcl_DecrRefCount(objResultPtr); instOriginError: Tcl_SetObjResult(interp, Tcl_ObjPrintf( "invalid command name \"%s\"", TclGetString(OBJ_AT_TOS))); DECACHE_STACK_INFO(); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "COMMAND", TclGetString(OBJ_AT_TOS), NULL); CACHE_STACK_INFO(); TRACE_APPEND(("ERROR: not command\n")); goto gotError; } TRACE_APPEND(("\"%.30s\"", O2S(OBJ_AT_TOS))); NEXT_INST_F(1, 1, 1); } /* * ----------------------------------------------------------------- * Start of TclOO support instructions. |
︙ | ︙ |
Changes to generic/tclInt.h.
︙ | ︙ | |||
1703 1704 1705 1706 1707 1708 1709 | * command. */ Tcl_ObjCmdProc *nreProc; /* NRE implementation of this command. */ } Command; /* * Flag bits for commands. * | | | | | | | 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 | * command. */ Tcl_ObjCmdProc *nreProc; /* NRE implementation of this command. */ } Command; /* * Flag bits for commands. * * CMD_DYING - If 1 the command is in the process of * being deleted (its deleteProc is currently * executing). Other attempts to delete the * command should be ignored. * CMD_TRACE_ACTIVE - If 1 the trace processing is currently * underway for a rename/delete change. See the * two flags below for which is currently being * processed. * CMD_HAS_EXEC_TRACES - If 1 means that this command has at least one * execution trace (as opposed to simple * delete/rename traces) in its tracePtr list. * CMD_COMPILES_EXPANDED - If 1 this command has a compiler that * can handle expansion (provided it is not the * first word). * TCL_TRACE_RENAME - A rename trace is in progress. Further * recursive renames will not be traced. * TCL_TRACE_DELETE - A delete trace is in progress. Further * recursive deletes will not be traced. * (these last two flags are defined in tcl.h) */ #define CMD_DYING 0x01 #define CMD_TRACE_ACTIVE 0x02 #define CMD_HAS_EXEC_TRACES 0x04 #define CMD_COMPILES_EXPANDED 0x08 #define CMD_REDEF_IN_PROGRESS 0x10 #define CMD_VIA_RESOLVER 0x20 #define CMD_DEAD 0x40 |
︙ | ︙ | |||
4956 4957 4958 4959 4960 4961 4962 | /* *---------------------------------------------------------------- * Inline version of TclCleanupCommand; still need the function as it is in * the internal stubs, but the core can use the macro instead. */ | | > | | > > | > > > > > > > > > > > > > > > > > | 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 | /* *---------------------------------------------------------------- * Inline version of TclCleanupCommand; still need the function as it is in * the internal stubs, but the core can use the macro instead. */ #define TclCleanupCommandMacro(cmdPtr) \ do { \ if ((cmdPtr)->refCount-- <= 1) { \ ckfree(cmdPtr); \ } \ } while (0) /* * inside this routine crement refCount first incase cmdPtr is replacing itself */ #define TclRoutineAssign(location, cmdPtr) \ do { \ (cmdPtr)->refCount++; \ if ((location) != NULL \ && (location--) <= 1) { \ ckfree(((location))); \ } \ (location) = (cmdPtr); \ } while (0) #define TclRoutineHasName(cmdPtr) \ (cmdPtr)->hPtr != NULL /* *---------------------------------------------------------------- * Inline versions of Tcl_LimitReady() and Tcl_LimitExceeded to limit number * of calls out of the critical path. Note that this code isn't particularly * readable; the non-inline version (in tclInterp.c) is much easier to * understand. Note also that these macros takes different args (iPtr->limit) |
︙ | ︙ |
Changes to generic/tclNamesp.c.
︙ | ︙ | |||
1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 | } dataPtr = (ImportedCmdData *)ckalloc(sizeof(ImportedCmdData)); importedCmd = Tcl_NRCreateCommand(interp, Tcl_DStringValue(&ds), TclInvokeImportedCmd, InvokeImportedNRCmd, dataPtr, DeleteImportedCmd); dataPtr->realCmdPtr = cmdPtr; dataPtr->selfPtr = (Command *) importedCmd; dataPtr->selfPtr->compileProc = cmdPtr->compileProc; Tcl_DStringFree(&ds); /* * Create an ImportRef structure describing this new import command * and add it to the import ref list in the "real" command. | > > | 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 | } dataPtr = (ImportedCmdData *)ckalloc(sizeof(ImportedCmdData)); importedCmd = Tcl_NRCreateCommand(interp, Tcl_DStringValue(&ds), TclInvokeImportedCmd, InvokeImportedNRCmd, dataPtr, DeleteImportedCmd); dataPtr->realCmdPtr = cmdPtr; /* corresponding decrement is in DeleteImportedCmd */ cmdPtr->refCount++; dataPtr->selfPtr = (Command *) importedCmd; dataPtr->selfPtr->compileProc = cmdPtr->compileProc; Tcl_DStringFree(&ds); /* * Create an ImportRef structure describing this new import command * and add it to the import ref list in the "real" command. |
︙ | ︙ | |||
2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 | if (prevPtr == NULL) { /* refPtr is first in list. */ realCmdPtr->importRefPtr = refPtr->nextPtr; } else { prevPtr->nextPtr = refPtr->nextPtr; } ckfree(refPtr); ckfree(dataPtr); return; } prevPtr = refPtr; } Tcl_Panic("DeleteImportedCmd: did not find cmd in real cmd's list of import references"); | > | 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 | if (prevPtr == NULL) { /* refPtr is first in list. */ realCmdPtr->importRefPtr = refPtr->nextPtr; } else { prevPtr->nextPtr = refPtr->nextPtr; } ckfree(refPtr); TclCleanupCommandMacro(realCmdPtr); ckfree(dataPtr); return; } prevPtr = refPtr; } Tcl_Panic("DeleteImportedCmd: did not find cmd in real cmd's list of import references"); |
︙ | ︙ | |||
3884 3885 3886 3887 3888 3889 3890 | static int NamespaceOriginCmd( TCL_UNUSED(ClientData), Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { | | | | > > > > > > > > > > > < < < < < < < < < < < < < > | 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 | static int NamespaceOriginCmd( TCL_UNUSED(ClientData), Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { Tcl_Command cmd, origCmd; Tcl_Obj *resultPtr; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "name"); return TCL_ERROR; } cmd = Tcl_GetCommandFromObj(interp, objv[1]); if (cmd == NULL) { goto namespaceOriginError; } origCmd = TclGetOriginalCommand(cmd); if (origCmd == NULL) { origCmd = cmd; } TclNewObj(resultPtr); Tcl_GetCommandFullName(interp, origCmd, resultPtr); if (TclCheckEmptyString(resultPtr) == TCL_EMPTYSTRING_YES ) { Tcl_DecrRefCount(resultPtr); namespaceOriginError: Tcl_SetObjResult(interp, Tcl_ObjPrintf( "invalid command name \"%s\"", TclGetString(objv[1]))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "COMMAND", TclGetString(objv[1]), NULL); return TCL_ERROR; } Tcl_SetObjResult(interp, resultPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * NamespaceParentCmd -- * * Invoked to implement the "namespace parent" command that returns the |
︙ | ︙ |
Changes to generic/tclOO.c.
︙ | ︙ | |||
1173 1174 1175 1176 1177 1178 1179 | /* * Instruct everyone to no longer use any allocated fields of the object. * Also delete the command that refers to the object at this point (if it * still exists) because otherwise its pointer to the object points into * freed memory. */ | | | 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 | /* * Instruct everyone to no longer use any allocated fields of the object. * Also delete the command that refers to the object at this point (if it * still exists) because otherwise its pointer to the object points into * freed memory. */ if (((Command *) oPtr->command)->flags && CMD_DYING) { /* * Something has already started the command deletion process. We can * go ahead and clean up the the namespace, */ } else { /* * The namespace must have been deleted directly. Delete the command |
︙ | ︙ |
Changes to generic/tclObj.c.
︙ | ︙ | |||
4663 4664 4665 4666 4667 4668 4669 | Tcl_FindCommand(interp, name, /*ns*/ NULL, /*flags*/ 0); /* * Stop shimmering and caching nothing when we found nothing. Just * report the failure to find the command as an error. */ | | | 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 | Tcl_FindCommand(interp, name, /*ns*/ NULL, /*flags*/ 0); /* * Stop shimmering and caching nothing when we found nothing. Just * report the failure to find the command as an error. */ if (cmdPtr == NULL || !TclRoutineHasName(cmdPtr)) { return TCL_ERROR; } resPtr = (ResolvedCmdName *)objPtr->internalRep.twoPtrValue.ptr1; if ((objPtr->typePtr == &tclCmdNameType) && (resPtr->refCount == 1)) { /* * Re-use existing ResolvedCmdName struct when possible. |
︙ | ︙ |
Changes to tests/namespace.test.
︙ | ︙ | |||
611 612 613 614 615 616 617 618 619 620 621 622 623 624 | namespace eval src {namespace export foo; proc foo {} {}} namespace eval dst {namespace import [namespace parent]::src::foo} trace add command src::foo delete \ "[list namespace delete [namespace current]::dst] ;#" proc src::foo {} {} namespace delete src } {} test namespace-14.1 {TclGetNamespaceForQualName, absolute names} -setup { catch {namespace delete {*}[namespace children :: test_ns_*]} variable v 10 namespace eval test_ns_1::test_ns_2 { variable v 20 } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 | namespace eval src {namespace export foo; proc foo {} {}} namespace eval dst {namespace import [namespace parent]::src::foo} trace add command src::foo delete \ "[list namespace delete [namespace current]::dst] ;#" proc src::foo {} {} namespace delete src } {} test namespace-13.3 { deleting origin of import in trace on deletion of import } -setup { namespace eval ns0 { namespace export * variable res {} proc traced {oldname newname op} { variable res lappend res {Is oldname the name of the imported routine?} set expected [namespace qualifiers [namespace current]::fake]::ns2::ns1 if {$oldname eq $expected} { lappend res 1 } else { lappend res 0 } lappend res {[namespace which] finds the old name} set which [namespace which $oldname] if {$which eq $expected} { lappend res 1 } else { lappend res $which } lappend res {Is origin name correct} catch { namespace origin $oldname } cres copts set expected [namespace qualifiers [namespace current]::fake]::ns1 if {$cres eq $expected} { lappend res 1 } else { lappend res $cres } set origin $cres rename $origin {} lappend res {After deletion of the origin is it an error to ask for the origin (compiled)?} set status [catch { namespace origin $oldname } cres copts] if {$status && [string match {invalid command name "*::ns2::ns1"} $cres]} { lappend res 1 } else { lappend res $cres } lappend res {After deletion of the origin is it an error to ask for the origin (uncompiled)?} set status [catch { namespace eval [namespace current] "namespace origin $oldname" } cres copts] if {$status && [string match {invalid command name "*::ns2::ns1"} $cres]} { lappend res 1 } else { lappend res $cres } lappend res {after deletion of origin, [namespace which] on the imported routine returns the empty string} set which [namespace which $oldname] if {$which eq {}} { lappend res 1 } else { lappend res $which } return } } } -body { namespace eval ns0::ns1 { namespace ensemble create } namespace eval ns0::ns2 { namespace import [namespace parent]::ns1 trace add command ns1 delete [namespace parent]::traced rename ns1 {} } return $ns0::res } -cleanup { namespace delete ns0 } -result [list \ {Is oldname the name of the imported routine?} 1 \ {[namespace which] finds the old name} 1 \ {Is origin name correct} 1 \ {After deletion of the origin is it an error to ask for the origin (compiled)?} 1 \ {After deletion of the origin is it an error to ask for the origin (uncompiled)?} 1 \ {after deletion of origin, [namespace which] on the imported routine returns the empty string} 1 \ ] test namespace-14.1 {TclGetNamespaceForQualName, absolute names} -setup { catch {namespace delete {*}[namespace children :: test_ns_*]} variable v 10 namespace eval test_ns_1::test_ns_2 { variable v 20 } |
︙ | ︙ |