]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
commit bash-20180309 snapshot
authorChet Ramey <chet.ramey@case.edu>
Mon, 12 Mar 2018 12:10:29 +0000 (08:10 -0400)
committerChet Ramey <chet.ramey@case.edu>
Mon, 12 Mar 2018 12:10:29 +0000 (08:10 -0400)
22 files changed:
CWRU/CWRU.chlog
MANIFEST
Makefile.in
builtins/Makefile.in
builtins/declare.def
builtins/shopt.def
lib/glob/Makefile.in
lib/readline/Makefile.in
lib/readline/bind.c
lib/sh/Makefile.in
tests/RUN-ONE-TEST
tests/array.right
tests/array.tests
tests/array25.sub [new file with mode: 0644]
tests/errors.right
tests/errors6.sub
tests/nameref.right
tests/nameref19.sub [new file with mode: 0644]
tests/varenv.right
tests/varenv.sh
tests/varenv10.sub [new file with mode: 0644]
variables.c

index fdb6ee2564e78d7e7261b0ee50735f9f143b0a73..6b074002d8cbbf1627bd91da2104f9098d562b83 100644 (file)
@@ -15047,3 +15047,25 @@ subst.c
          we are checking whether value is null, so we can have different
          error messages for ${x:?} and ${x?}. Report and fix from
          don fong <dfong@dfong.com>
+
+                                   3/5
+                                   ---
+lib/readline/bind.c
+       - _rl_read_file: instead of calling stat/open on the passed filename,
+         use open/fstat to avoid one possible filename translation and close
+         a small (benign) race condition. Report and fix from Roy Ivy
+         <roy.ivy.iii@gmail.com>
+
+                                  3/11
+                                  ----
+variables.c
+       - makunbound: if new variable localvar_unset is non-zero, mark local
+         vars in previous scopes as invisible and unset so they will show
+         up as unset until that previous scope returns (similar to how local
+         variables in the current local scope are handled). localvar_unset
+         is currently set to 0 with no way for a script to change its value.
+         Eventually there will be an option to modify it.  From a bug-bash
+         discussion started by Nikolai Kondrashov <spbnick@gmail.com> back
+         on 2/11/2018
+
+
index 5f635812096e47521fe71d6e79cd88fdf342747b..93d7c0f287d1f0e8e44c5025a9dc2a93273083cf 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -864,6 +864,7 @@ tests/array21.sub   f
 tests/array22.sub      f
 tests/array23.sub      f
 tests/array24.sub      f
+tests/array25.sub      f
 tests/array-at-star    f
 tests/array2.right     f
 tests/assoc.tests      f
@@ -1125,6 +1126,7 @@ tests/nameref15.sub       f
 tests/nameref16.sub    f
 tests/nameref17.sub    f
 tests/nameref18.sub    f
+tests/nameref19.sub    f
 tests/nameref.right    f
 tests/new-exp.tests    f
 tests/new-exp1.sub     f
@@ -1348,6 +1350,7 @@ tests/varenv6.sub f
 tests/varenv7.sub      f
 tests/varenv8.sub      f
 tests/varenv9.sub      f
+tests/varenv10.sub     f
 tests/version          f
 tests/version.mini     f
 tests/vredir.tests     f
index f86ebc1e0632a502320fee2ebcd2cdf84bc98680..80dd91662ffb93e606a3527df19561163352dcb0 100644 (file)
@@ -148,17 +148,20 @@ SYSTEM_FLAGS = -DPROGRAM='"$(Program)"' -DCONF_HOSTTYPE='"$(Machine)"' -DCONF_OS
 BASE_CCFLAGS = $(SYSTEM_FLAGS) $(LOCAL_DEFS) \
          $(DEFS) $(LOCAL_CFLAGS) $(INCLUDES)
 
-CCFLAGS = $(ASAN_CFLAGS) $(BASE_CCFLAGS) ${PROFILE_FLAGS} $(CPPFLAGS) $(CFLAGS)
+CCFLAGS = $(ADDON_CFLAGS) $(BASE_CCFLAGS) ${PROFILE_FLAGS} $(CPPFLAGS) $(CFLAGS)
 
 CCFLAGS_FOR_BUILD = $(BASE_CCFLAGS) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD)
 
 BASE_LDFLAGS = @LDFLAGS@ $(LOCAL_LDFLAGS) $(CFLAGS)
-LDFLAGS = ${ASAN_LDFLAGS} ${BASE_LDFLAGS} ${PROFILE_FLAGS} ${STATIC_LD}
+LDFLAGS = ${ADDON_LDFLAGS} ${BASE_LDFLAGS} ${PROFILE_FLAGS} ${STATIC_LD}
 LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@ $(LOCAL_LDFLAGS) $(CFLAGS_FOR_BUILD)
 
 ASAN_XCFLAGS = -fsanitize=address -fno-omit-frame-pointer
 ASAN_XLDFLAGS = -fsanitize=address
 
+GCOV_XCFLAGS = -fprofile-arcs -ftest-coverage
+GCOV_XLDFLAGS = -fprofile-arcs -ftest-coverage
+
 INCLUDES = -I. @RL_INCLUDE@ -I$(srcdir) -I$(BASHINCDIR) -I$(LIBSRC) $(INTL_INC)
 
 # Maybe add: -Wextra
@@ -602,7 +605,12 @@ lint:
        ${MAKE} ${MFLAGS} CFLAGS='${GCC_LINT_FLAGS}' .made
 
 asan:
-       ${MAKE} ${MFLAGS} ASAN_CFLAGS='${ASAN_XCFLAGS}' ASAN_LDFLAGS='${ASAN_XLDFLAGS}' .made
+       ${MAKE} ${MFLAGS} ADDON_CFLAGS='${ASAN_XCFLAGS}' ADDON_LDFLAGS='${ASAN_XLDFLAGS}' .made
+
+# cheating
+gcov:
+       ${MAKE} ${MFLAGS} ADDON_CFLAGS='${GCOV_XCFLAGS}' ADDON_LDFLAGS='${GCOV_XLDFLAGS}' .made
+
 
 # have to make this separate because making tests depend on $(PROGRAM)
 asan-tests: asan  $(TESTS_SUPPORT)
@@ -611,6 +619,10 @@ asan-tests: asan  $(TESTS_SUPPORT)
        @( cd $(srcdir)/tests && \
                PATH=$(BUILD_DIR)/tests:$$PATH THIS_SH=$(THIS_SH) $(SHELL) ${TESTSCRIPT} )
 
+profiling-tests:       ${PROGRAM}
+       @test "X$$PROFILE_FLAGS" == "X" && { echo "profiling-tests: must be built with profiling enabled" >&2; exit 1; }
+       @${MAKE} ${MFLAGS} tests TESTSCRIPT=run-gprof
+
 version.h:  $(SOURCES) config.h Makefile patchlevel.h
        $(SHELL) $(SUPPORT_SRC)mkversion.sh -b -S ${topdir} -s $(RELSTATUS) -d $(Version) -o newversion.h \
                && mv newversion.h version.h
index d86a69b501e86ed9f816c504e9ed2452d3f0a098..388ca4eb0c03be985fc0f12734a13bf9fad3d249 100644 (file)
@@ -94,7 +94,7 @@ INCLUDES = -I. -I.. @RL_INCLUDE@ -I$(topdir) -I$(BASHINCDIR) -I$(topdir)/lib -I$
 BASE_CCFLAGS = ${PROFILE_FLAGS} $(DEFS) $(LOCAL_DEFS) $(SYSTEM_FLAGS) \
         ${INCLUDES} $(LOCAL_CFLAGS)
 
-CCFLAGS = ${ASAN_CFLAGS} $(BASE_CCFLAGS) $(CPPFLAGS) $(CFLAGS)
+CCFLAGS = ${ADDON_CFLAGS} $(BASE_CCFLAGS) $(CPPFLAGS) $(CFLAGS)
 
 CCFLAGS_FOR_BUILD = $(BASE_CCFLAGS) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD)
 
index b56f24881130b6e84115d0edc5b549873902829f..2574eba4df604186d65bde3c345f899c7e155e8b 100644 (file)
@@ -573,8 +573,9 @@ restart_new_var_name:
            }
          /* However, if we're turning off the nameref attribute on an existing
             nameref variable, we first follow the nameref chain to the end,
-            modify the value of the variable this nameref variable references,
-            *CHANGING ITS VALUE AS A SIDE EFFECT* then turn off the nameref
+            modify the value of the variable this nameref variable references
+            if there is an assignment statement argument,
+            *CHANGING ITS VALUE AS A SIDE EFFECT*, then turn off the nameref
             flag *LEAVING THE NAMEREF VARIABLE'S VALUE UNCHANGED* */
          else if (var == 0 && (flags_off & att_nameref))
            {
@@ -592,6 +593,16 @@ restart_new_var_name:
                  any_failed++;
                  NEXT_VARIABLE ();
                }
+
+             /* If all we're doing is turning off the nameref attribute, don't
+                bother with VAR at all, whether it exists or not. Just turn it
+                off and go on. */
+             if (refvar && flags_on == 0 && offset == 0 && (flags_off & ~att_nameref) == 0)
+               {
+                 VUNSETATTR (refvar, att_nameref);
+                 NEXT_VARIABLE ();
+               }
+
              if (refvar)
                /* XXX - use declare_find_variable here? */
                var = mkglobal ? find_global_variable (nameref_cell (refvar)) : find_variable (nameref_cell (refvar));
@@ -671,6 +682,12 @@ restart_new_var_name:
                      value = name + namelen;
                    }
                  free (oldname);
+
+                 /* OK, let's turn off the nameref attribute.
+                    Now everything else applies to VAR. */
+                 if (flags_off & att_nameref)
+                   VUNSETATTR (refvar, att_nameref);
+
                  goto restart_new_var_name;
                  /* NOTREACHED */
                }
index e51c50012ff7b4125357a0e398a22341e43bc996..467dc53449fc8e3b7840ceb43fc7c5b6017ee649 100644 (file)
@@ -92,6 +92,7 @@ extern int glob_asciirange;
 extern int lastpipe_opt;
 extern int inherit_errexit;
 extern int localvar_inherit;
+extern int localvar_unset;
 
 #if defined (EXTENDED_GLOB)
 extern int extended_glob;
@@ -214,6 +215,9 @@ static struct {
   { "lithist", &literal_history, (shopt_set_func_t *)NULL },
 #endif
   { "localvar_inherit", &localvar_inherit, (shopt_set_func_t *)NULL },
+#if 0
+  { "localvar_unset", &localvar_unset, (shopt_set_func_t *)NULL },
+#endif
   { "login_shell", &shopt_login_shell, set_login_shell },
   { "mailwarn", &mail_warning, (shopt_set_func_t *)NULL },
 #if defined (READLINE)
index da28505bac487decefb3b535ea0c2a0f3ad162a0..314622f13e54d65f0a13989ef4c7e384365a816f 100644 (file)
@@ -53,7 +53,7 @@ BASHINCDIR = ${topdir}/include
 INCLUDES = -I. -I../.. -I$(topdir) -I$(BASHINCDIR) -I$(topdir)/lib
 
 CCFLAGS = $(PROFILE_FLAGS) $(DEFS) $(LOCAL_DEFS) ${INCLUDES} $(CPPFLAGS) \
-         $(LOCAL_CFLAGS) $(CFLAGS) ${ASAN_CFLAGS}
+         $(LOCAL_CFLAGS) $(CFLAGS) ${ADDON_CFLAGS}
 
 # Here is a rule for making .o files from .c files that doesn't force
 # the type of the machine (like -sun3) into the flags.
index 08441a0de6e50092754abfbe266e255ad2e12726..b2358c67ac2c18a1a5ef1dc0375994dfc64b0f7d 100644 (file)
@@ -65,7 +65,7 @@ LOCAL_DEFS = @LOCAL_DEFS@
 INCLUDES = -I. -I$(BUILD_DIR) -I$(topdir) -I$(topdir)/lib
 
 CCFLAGS = $(DEFS) $(LOCAL_DEFS) $(APP_CFLAGS) $(CPPFLAGS) ${INCLUDES} \
-         $(LOCAL_CFLAGS) $(CFLAGS) ${ASAN_CFLAGS}
+         $(LOCAL_CFLAGS) $(CFLAGS) ${ADDON_CFLAGS}
 
 .c.o:
        ${RM} $@
index 30779966850cb9cb5e7ff0c896ff697450ef5ab3..ef3331b80fafc2c4855a3959690574ddae0a9da4 100644 (file)
@@ -839,8 +839,13 @@ _rl_read_file (char *filename, size_t *sizep)
   char *buffer;
   int i, file;
 
-  if ((stat (filename, &finfo) < 0) || (file = open (filename, O_RDONLY, 0666)) < 0)
-    return ((char *)NULL);
+  file = -1;
+  if (((file = open (filename, O_RDONLY, 0666)) < 0) || (fstat (file, &finfo) < 0))
+    {
+      if (file >= 0)
+       close (file);
+      return ((char *)NULL);
+    }
 
   file_size = (size_t)finfo.st_size;
 
index 9870dcd61634f0b6a63de6b01d8d569a318f430c..b1a086d6fd958c01ef0b46276c4ec2d0975a0940 100644 (file)
@@ -67,7 +67,7 @@ LOCAL_DEFS = @LOCAL_DEFS@
 
 INCLUDES = -I. -I../.. -I$(topdir) -I$(topdir)/lib -I$(BASHINCDIR) -I$(srcdir) $(INTL_INC)
 
-CCFLAGS = ${ASAN_CFLAGS} ${PROFILE_FLAGS} ${INCLUDES} $(DEFS) $(LOCAL_DEFS) \
+CCFLAGS = ${ADDON_CFLAGS} ${PROFILE_FLAGS} ${INCLUDES} $(DEFS) $(LOCAL_DEFS) \
          $(LOCAL_CFLAGS) $(CFLAGS) $(CPPFLAGS) 
 
 GCC_LINT_FLAGS = -Wall -Wshadow -Wpointer-arith -Wcast-qual \
index 58c375b70d886bcff86f789ae4a15eee397f87c8..554f3d6ecc09d7149b13daa2d36a6bab1480269f 100755 (executable)
@@ -1,4 +1,4 @@
-BUILD_DIR=/usr/local/build/chet/bash/bash-current
+BUILD_DIR=/usr/local/build/bash/bash-current
 THIS_SH=$BUILD_DIR/bash
 PATH=$PATH:$BUILD_DIR
 
index 3aab592d9b924c5f5d9a178419d9dc361cfbe9d8..ef3d49e2d7481b04883e7b667c55770f133fe09e 100644 (file)
@@ -577,3 +577,47 @@ jkl
 abc
 def ghi
 jkl
+1. indexed:
+reference:
+./array25.sub: line 10: ${a[ ]}: bad substitution
+./array25.sub: line 11: ' ': syntax error: operand expected (error token is "' '")
+./array25.sub: line 12: ${a[ ]}: bad substitution
+4. 0
+5. 0
+6. 0
+assignment:
+1.declare -a a=([0]="10" [1]="1")
+2.declare -a a=([0]="11" [1]="1")
+3.declare -a a=([0]="12" [1]="1")
+4.declare -a a=([0]="13" [1]="1")
+arithmetic:
+1.declare -a a=([0]="0" [1]="1")
+2.declare -a a=([0]="0" [1]="1")
+3.declare -a a=([0]="0" [1]="1")
+4.declare -a a=([0]="0" [1]="1")
+5.declare -a a=([0]="0" [1]="1")
+6.declare -a a=([0]="11" [1]="1")
+7.declare -a a=([0]="0" [1]="1")
+8.declare -a a=([0]="13" [1]="1")
+2. associative:
+reference:
+./array25.sub: line 47: ${a[ ]}: bad substitution
+2.
+./array25.sub: line 49: ${a[ ]}: bad substitution
+4.
+5.
+6. 
+assignment:
+1.declare -A a=([" "]="10" [0]="0" [1]="1" )
+2.declare -A a=([" "]="11" [0]="0" [1]="1" )
+3.declare -A a=([" "]="12" [0]="0" [1]="1" )
+4.declare -A a=([" "]="13" [0]="0" [1]="1" )
+arithmetic:
+1.declare -A a=([" "]="13" [0]="0" [1]="1" )
+2.declare -A a=([" "]="13" [0]="0" [1]="1" )
+3.declare -A a=([" "]="13" [0]="0" [1]="1" )
+4.declare -A a=([" "]="13" [0]="0" [1]="1" )
+5.declare -A a=([" "]="13" [0]="0" [1]="1" )
+6.declare -A a=([" "]="13" [0]="0" [1]="1" ["\" \""]="11" )
+7.declare -A a=([" "]="13" [0]="0" [1]="1" ["\" \""]="11" )
+8.declare -A a=([" "]="13" [0]="0" [1]="1" ["\" \""]="13" )
index 9f5dd6a33379db545133a0089ef3014be741e58b..c909a4f0baad954932e35f52283ccde1ba8f9876 100644 (file)
@@ -400,3 +400,4 @@ ${THIS_SH} ./array21.sub
 ${THIS_SH} ./array22.sub
 ${THIS_SH} ./array23.sub
 ${THIS_SH} ./array24.sub
+${THIS_SH} ./array25.sub
diff --git a/tests/array25.sub b/tests/array25.sub
new file mode 100644 (file)
index 0000000..b550d9d
--- /dev/null
@@ -0,0 +1,70 @@
+# tests with blank subscripts, indexed and associative
+
+echo 1. indexed:
+a[0]=0 a[1]=1
+
+v=" "
+
+echo reference:
+
+echo 1. ${a[ ]}
+echo 2. ${a[' ']}
+echo 3. "${a[ ]}"
+echo 4. ${a[$v]}
+echo 5. ${a["$v"]}
+echo 6. "${a[$v]}"
+
+echo assignment:
+
+echo -n 1. ; a[ ]=10 ; typeset -p a ; a[0]=0
+echo -n 2. ; a[" "]=11 ; typeset -p a ; a[0]=0
+echo -n 3. ; a[$v]=12 ; typeset -p a ; a[0]=0
+echo -n 4. ; a["$v"]=13 ; typeset -p a ; a[0]=0
+
+echo arithmetic:
+
+echo -n 1. ; (( a[ ]=10 )); typeset -p a ; a[0]=0
+echo -n 2. ; (( a[" "]=11 )); typeset -p a ; a[0]=0
+echo -n 3. ; (( a[$v]=12 )); typeset -p a ; a[0]=0
+echo -n 4. ; (( a["$v"]=13 )); typeset -p a ; a[0]=0
+echo -n 5. ; let "a[ ]=10" ; typeset -p a ; a[0]=0
+echo -n 6. ; let "a[\" \"]=11" ; typeset -p a ; a[0]=0
+echo -n 7. ; let "a[$v]=12" ; typeset -p a ; a[0]=0
+echo -n 8. ; let "a[\"$v\"]=13" ; typeset -p a ; a[0]=0
+
+unset -v a v
+
+echo 2. associative:
+shopt -s assoc_expand_once
+
+typeset -A a
+a[0]=0 a[1]=1
+
+v=" "
+
+echo reference:
+
+echo 1. ${a[ ]}
+echo 2. ${a[' ']}
+echo 3. "${a[ ]}"
+echo 4. ${a[$v]}
+echo 5. ${a["$v"]}
+echo 6. "${a[$v]}"
+
+echo assignment:
+
+echo -n 1. ; a[ ]=10 ; typeset -p a ; a[0]=0
+echo -n 2. ; a[" "]=11 ; typeset -p a ; a[0]=0
+echo -n 3. ; a[$v]=12 ; typeset -p a ; a[0]=0
+echo -n 4. ; a["$v"]=13 ; typeset -p a ; a[0]=0
+
+echo arithmetic:
+
+echo -n 1. ; (( a[ ]=10 )); typeset -p a ; a[0]=0
+echo -n 2. ; (( a[" "]=11 )); typeset -p a ; a[0]=0
+echo -n 3. ; (( a[$v]=12 )); typeset -p a ; a[0]=0
+echo -n 4. ; (( a["$v"]=13 )); typeset -p a ; a[0]=0
+echo -n 5. ; let "a[ ]=10" ; typeset -p a ; a[0]=0
+echo -n 6. ; let "a[\" \"]=11" ; typeset -p a ; a[0]=0
+echo -n 7. ; let "a[$v]=12" ; typeset -p a ; a[0]=0
+echo -n 8. ; let "a[\"$v\"]=13" ; typeset -p a ; a[0]=0
index c968c3132230a90561c0269b508d8b87f40d4214..403450eb30772faee532a9177427449df77094eb 100644 (file)
@@ -127,10 +127,22 @@ after 2: 1
 after 3: 1
 array after 1: 1
 array after 2: 1
-./errors6.sub: line 18: ${-3}: bad substitution
-./errors6.sub: line 19: -3: invalid variable name
+./errors6.sub: uvar: parameter not set
+./errors6.sub: uvar: parameter null or not set
+
+./errors6.sub: uvar: parameter null or not set
+./errors6.sub: line 25: ${-3:-${-3}}: bad substitution
+./errors6.sub: line 26: ${-3}: bad substitution
+./errors6.sub: line 27: -3: invalid variable name
 after indir: 1
-./errors6.sub: line 18: ${-3}: bad substitution
-./errors6.sub: line 19: -3: invalid variable name
+./errors6.sub: line 30: -3: invalid variable name
+./errors6.sub: uvar: parameter not set
+./errors6.sub: uvar: parameter null or not set
+
+./errors6.sub: uvar: parameter null or not set
+./errors6.sub: line 25: ${-3:-${-3}}: bad substitution
+./errors6.sub: line 26: ${-3}: bad substitution
+./errors6.sub: line 27: -3: invalid variable name
 after indir: 1
+./errors6.sub: line 30: -3: invalid variable name
 ./errors.tests: line 278: `!!': not a valid identifier
index 3c05625a4173fa9a495d37747664ddfe2116af9e..c08d41f1b19b51e60bd5d4b9829900468df904ba 100644 (file)
@@ -15,6 +15,17 @@ echo array after 1: $?'  2>/dev/null
 ${THIS_SH} -c 'typeset -A v ; v["0"]=one ; echo ${v[   ]}
 echo array after 2: $?'  2>/dev/null
 
+${THIS_SH} -c 'echo ${uvar?}' ./errors6.sub
+${THIS_SH} -c 'echo ${uvar:?}' ./errors6.sub
+export uvar=
+${THIS_SH} -c 'echo ${uvar?}' ./errors6.sub
+${THIS_SH} -c 'echo ${uvar:?}' ./errors6.sub
+unset uvar
+
+echo "${-3:-${-3}}"
 echo ${-3}
 x=-3; echo ${!x}
 echo after indir: $?
+
+function ivar() { echo -n "${!1:-${1}}"; }
+ivar -3
index 220b1b509f9eeec65db54e95cb63b7aaf1a3f951..0ff122239da64074db0ca32dfd790f285e45b321 100644 (file)
@@ -417,3 +417,19 @@ declare -a var=([123]="")
 declare -n ref="var[123]"
 ./nameref18.sub: line 54: declare: var[123]: not found
 declare -a var=([123]="X")
+declare -n foo="bar"
+declare -- foo="bar"
+./nameref19.sub: line 9: declare: bar: not found
+declare -n foo="bar"
+declare -- foo="bar"
+declare -i bar="11"
+declare -inx foo6
+declare -ix foo6
+declare -n foo="bar"
+declare -- bar="Hello World!"
+declare -- foo="bar"
+declare -- bar="Hello World!"
+declare -n foo="bar"
+declare -- bar
+declare -- foo="bar"
+declare -- bar
diff --git a/tests/nameref19.sub b/tests/nameref19.sub
new file mode 100644 (file)
index 0000000..d46c003
--- /dev/null
@@ -0,0 +1,51 @@
+# can we unset the nameref attribute on variables with values that reference
+# unset variables?
+
+unset bar
+declare -n foo="bar"
+declare -p foo
+
+declare +n foo
+declare -p foo bar
+
+declare -n foo
+declare -p foo
+
+# let's try removing the nameref attribute -- other attributes and assignments
+# apply to the nameref target
+
+declare +n -i foo=7+4
+declare -p foo bar
+
+unset foo bar
+
+# but if the nameref variable doesn't have a value, the attributes apply to
+# the nameref variable itself. thanks ksh93
+
+declare -n foo6
+declare -xi foo6
+declare -p foo6
+
+# and when we remove the nameref attribute, the other attributes remain
+
+declare +n foo6
+declare -p foo6
+
+unset foo6
+
+# make sure these cases continue to work
+
+# nameref referencing an existing, set variable
+declare -n foo=bar
+bar='Hello World!'
+declare -p foo bar
+declare +n foo
+declare -p foo bar
+unset foo bar
+
+# nameref referencing an existing, unset variable
+declare -n foo=bar
+declare bar
+declare -p foo bar
+declare +n foo
+declare -p foo bar
index 1d75239f075532a61e83548bea00f8bdcaea8973..c0ff664fd45b60490afd801fb3bdf0aaec37f620 100644 (file)
@@ -119,6 +119,15 @@ declare -ar i4=([0]="a" [1]="b" [2]="c")
 declare -ar j4=([0]="1" [1]="2" [2]="3")
 ./varenv9.sub: line 66: unset: i4: cannot unset: readonly variable
 ./varenv9.sub: line 66: unset: j4: cannot unset: readonly variable
+main: unset
+inner: res unset
+outer: res: X Y
+main: after first call: X
+inner: X
+outer: res: X Y
+main: after second call: X
+func: null or unset
+after func: x = outside
 a=z
 a=b
 a=z
index 180ee1f67c72438b9dea7562c0fed0b45085f660..cbfbed09e5caf59f6901fdc50598500ff065dcad 100644 (file)
@@ -225,5 +225,8 @@ ${THIS_SH} ./varenv8.sub
 # if executed in shell functions, like they modify local scalar variables
 ${THIS_SH} ./varenv9.sub
 
+# more tests of unset and local variables with dynamic scoping
+${THIS_SH} ./varenv10.sub
+
 # make sure variable scoping is done right
 tt() { typeset a=b;echo a=$a; };a=z;echo a=$a;tt;echo a=$a
diff --git a/tests/varenv10.sub b/tests/varenv10.sub
new file mode 100644 (file)
index 0000000..887cfd2
--- /dev/null
@@ -0,0 +1,47 @@
+#!/bin/bash
+#
+# various tests of unset when applied to variables at different local scopes
+
+# function unsetting variable at previous local scope, uncovering global
+
+inner()
+{
+    unset res
+    echo ${FUNCNAME}: ${res-res unset}
+    if [[ $1 == "set" ]]; then
+        res[0]="X"
+        res[1]="Y"
+    fi
+}
+
+outer()
+{
+    local res=
+    inner "$1"
+    echo ${FUNCNAME}: "res: ${res[@]}"
+}
+
+echo main: ${res-unset}
+outer set
+echo main: after first call: ${res-unset}
+outer dontset 
+echo main: after second call: ${res-unset}
+
+unset -f outer inner
+unset res
+
+# local scope, unset variable at the same scope as local declaration
+func()
+{
+       typeset x=4
+
+       unset x
+       echo ${FUNCNAME}: ${x:-null or unset}
+}
+
+x=outside
+func
+echo after func: x = $x
+
+unset -f func
+unset x
index 0c35105f84681db111696dc9db52897e709f624f..1c7b09ac43cd14c68d3e51b3d79c884e3e0d934e 100644 (file)
@@ -124,6 +124,11 @@ int variable_context = 0;
    with the same name at a previous scope. */
 int localvar_inherit = 0;
 
+/* If non-zero, calling `unset' on local variables in previous scopes marks
+   them as invisible so lookups find them unset. This is the same behavior
+   as local variables in the current local scope. */
+int localvar_unset = 0;
+
 /* The set of shell assignments which are made only in the environment
    for a single command. */
 HASH_TABLE *temporary_env = (HASH_TABLE *)NULL;
@@ -3706,7 +3711,8 @@ makunbound (name, vc)
      must be done so that if the variable is subsequently assigned a new
      value inside the function, the `local' attribute is still present.
      We also need to add it back into the correct hash table. */
-  if (old_var && local_p (old_var) && variable_context == old_var->context)
+  if (old_var && local_p (old_var) &&
+       (old_var->context == variable_context || (localvar_unset && old_var->context < variable_context)))
     {
       if (nofree_p (old_var))
        var_setvalue (old_var, (char *)NULL);