Tcl Source Code

Artifact [e75621b48d]
Login

Artifact e75621b48da63d52eb2fb9aa78b65aad2fe57974:

Attachment "diff" to ticket [631741ffff] added by msofer 2003-03-25 04:34:58.
Index: generic/tclVar.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclVar.c,v
retrieving revision 1.69
diff -u -r1.69 tclVar.c
--- generic/tclVar.c	12 Nov 2002 02:23:03 -0000	1.69
+++ generic/tclVar.c	24 Mar 2003 00:39:51 -0000
@@ -21,6 +21,7 @@
 #include "tclInt.h"
 #include "tclPort.h"
 
+
 /*
  * The strings below are used to indicate what went wrong when a
  * variable access is denied.
@@ -55,7 +56,7 @@
 static int              ObjMakeUpvar _ANSI_ARGS_((Tcl_Interp *interp, 
                             CallFrame *framePtr, Tcl_Obj *otherP1Ptr, 
                             CONST char *otherP2, CONST int otherFlags,
-		            CONST char *myName, CONST int myFlags, int index));
+		            CONST char *myName, int myFlags, int index));
 static Var *		NewVar _ANSI_ARGS_((void));
 static ArraySearch *	ParseSearchId _ANSI_ARGS_((Tcl_Interp *interp,
 			    CONST Var *varPtr, CONST char *varName,
@@ -596,6 +597,16 @@
 }
 
 /*
+ * This flag bit should not interfere with TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY,
+ * or TCL_LEAVE_ERR_MSG; it signals that the variable lookup is performed for 
+ * upvar (or similar) purposes, with slightly different rules:
+ *   - Bug #696893 - variable is either proc-local or in the current
+ *     namespace; never follow the second (global) resolution path 
+ *   - Bug #631741 - do not use special namespace or interp resolvers
+ */
+#define LOOKUP_FOR_UPVAR 0x400
+
+/*
  *----------------------------------------------------------------------
  *
  * TclLookupSimpleVar --
@@ -642,7 +653,8 @@
     CONST char *varName;        /* This is a simple variable name that could
 				 * representa scalar or an array. */
     int flags;		        /* Only TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY,
-				 * and TCL_LEAVE_ERR_MSG bits matter. */
+				 * LOOKUP_FOR_UPVAR and TCL_LEAVE_ERR_MSG bits 
+				 * matter. */
     CONST int create;		/* If 1, create hash table entry for varname,
 				 * if it doesn't already exist. If 0, return 
 				 * error if it doesn't exist. */
@@ -669,19 +681,21 @@
     varNsPtr = NULL;		/* set non-NULL if a nonlocal variable */
     *indexPtr = -3;
 
+    if ((flags & TCL_GLOBAL_ONLY) || iPtr->varFramePtr == NULL) {
+        cxtNsPtr = iPtr->globalNsPtr;
+    } else {
+        cxtNsPtr = iPtr->varFramePtr->nsPtr;
+    }
+
     /*
      * If this namespace has a variable resolver, then give it first
      * crack at the variable resolution.  It may return a Tcl_Var
      * value, it may signal to continue onward, or it may signal
      * an error.
      */
-    if ((flags & TCL_GLOBAL_ONLY) || iPtr->varFramePtr == NULL) {
-        cxtNsPtr = iPtr->globalNsPtr;
-    } else {
-        cxtNsPtr = iPtr->varFramePtr->nsPtr;
-    }
 
-    if (cxtNsPtr->varResProc != NULL || iPtr->resolverPtr != NULL) {
+    if ((cxtNsPtr->varResProc != NULL || iPtr->resolverPtr != NULL) 
+	    && !(flags & LOOKUP_FOR_UPVAR)) {
         resPtr = iPtr->resolverPtr;
 
         if (cxtNsPtr->varResProc) {
@@ -736,10 +750,15 @@
 	    || ((*varName == ':') && (*(varName+1) == ':'));
 	if (lookGlobal) {
 	    *indexPtr = -1;
-	    flags = (flags | TCL_GLOBAL_ONLY) & ~TCL_NAMESPACE_ONLY;
-	} else if (flags & TCL_NAMESPACE_ONLY) {
-	    *indexPtr = -2;
-	}
+	    flags = (flags | TCL_GLOBAL_ONLY) & ~(TCL_NAMESPACE_ONLY|LOOKUP_FOR_UPVAR);
+	} else {
+	    if (flags & LOOKUP_FOR_UPVAR) {
+		flags = (flags | TCL_NAMESPACE_ONLY) & ~LOOKUP_FOR_UPVAR;
+	    }
+	    if (flags & TCL_NAMESPACE_ONLY) {
+		*indexPtr = -2;
+	    }
+	} 
 
 	/*
 	 * Don't pass TCL_LEAVE_ERR_MSG, we may yet create the variable,
@@ -3458,7 +3477,7 @@
 				 * indicates scope of "other" variable. */
     CONST char *myName;		/* Name of variable which will refer to
 				 * otherP1/otherP2. Must be a scalar. */
-    CONST int myFlags;		/* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY:
+    int myFlags;		/* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY:
 				 * indicates scope of myName. */
     int index;                  /* If the variable to be linked is an indexed
 				 * scalar, this is its index. Otherwise, -1. */
@@ -3490,7 +3509,7 @@
 
     if (index >= 0) {
 	if (!varFramePtr->isProcCallFrame) {
-	    panic("ObjMakeUpVar called with an index outside from a proc.\n");
+	    panic("ObjMakeUpvar called with an index outside from a proc.\n");
 	}
 	varPtr = &(varFramePtr->compiledLocals[index]);
     } else {
@@ -3513,11 +3532,16 @@
 	}
 	
 	/*
-	 * Lookup and eventually create the new variable.
+	 * Lookup and eventually create the new variable. Set the flag bit
+	 * LOOKUP_FOR_UPVAR to indicate the special resolution rules for 
+	 * upvar purposes: 
+	 *   - Bug #696893 - variable is either proc-local or in the current
+	 *     namespace; never follow the second (global) resolution path 
+	 *   - Bug #631741 - do not use special namespace or interp resolvers
 	 */
 	
-	varPtr = TclLookupSimpleVar(interp, myName, myFlags, /*create*/ 1, 
-				    &errMsg, &index);
+	varPtr = TclLookupSimpleVar(interp, myName, (myFlags | LOOKUP_FOR_UPVAR), 
+	        /* create */ 1, &errMsg, &index);
 	if (varPtr == NULL) {
 	    VarErrMsg(interp, myName, NULL, "create", errMsg);
 	    return TCL_ERROR;
Index: tests/var.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/var.test,v
retrieving revision 1.20
diff -u -r1.20 var.test
--- tests/var.test	17 Oct 2002 17:41:45 -0000	1.20
+++ tests/var.test	24 Mar 2003 00:39:51 -0000
@@ -262,6 +262,16 @@
     set aaaaa 789789
     list [catch {upvar #0 aaaaa test_ns_fred::lnk} msg] $msg
 } {1 {can't create "test_ns_fred::lnk": parent namespace doesn't exist}}
+test var-3.10 {MakeUpvar, } {
+    namespace eval {} {
+	set bar 0
+	namespace eval foo upvar bar bar
+	set foo::bar 1
+	catch {list $bar $foo::bar} msg
+	unset ::aaaaa
+	set msg
+    }
+} {1 1}
 
 if {[info commands testgetvarfullname] != {}} {
     test var-4.1 {Tcl_GetVariableName, global variable} {