diff --git a/NEWS b/NEWS
index 7bc685bf..3ad3a39a 100644
--- a/NEWS
+++ b/NEWS
@@ -10,6 +10,7 @@ History of Yash
 ----------------------------------------------------------------------
 Yash 2.49
 
+  +  '--forlocal' option.
   *  Expansion of ""$*, ""$@, $*"", and $@"" now correctly yields an
      empty string rather than nothing when there are no positional
      parameters.
diff --git a/doc/_set.txt b/doc/_set.txt
index bb7876fe..dceb1198 100644
--- a/doc/_set.txt
+++ b/doc/_set.txt
@@ -126,6 +126,15 @@ enabled.
 This option enables link:expand.html#extendedglob[extension in pathname
 expansion].
 
+[[so-forlocal]]forlocal::
+(Enabled by default)
+If a link:syntax.html#for[for loop] is executed within a
+link:exec.html#function[function], this option causes the iteration variable
+to be created as a link:exec.html#localvar[local variable], even if the
+variable already exists globally.
+This option has no effect if the link:posix.html[POSIXly-correct mode] is
+active.
+
 [[so-glob]]glob (`+f`)::
 (Enabled by default)
 This option enables link:expand.html#glob[pathname expansion].
diff --git a/doc/exec.txt b/doc/exec.txt
index df18d98b..30ff0369 100644
--- a/doc/exec.txt
+++ b/doc/exec.txt
@@ -209,7 +209,8 @@ finishes.
 
 dfn:[Local variables] are temporary variables that are defined in a function
 and exist during the function execution only.
-They can be defined by the link:_typeset.html[typeset built-in].
+They can be defined by the link:_typeset.html[typeset built-in]
+or implicitly created by a link:syntax.html#for[for loop].
 They are removed when the function execution finishes.
 
 Local variables may _hide_ variables that have already been defined before
diff --git a/doc/posix.txt b/doc/posix.txt
index 7219b833..2c8349b4 100644
--- a/doc/posix.txt
+++ b/doc/posix.txt
@@ -35,9 +35,9 @@ When the POSIXly-correct mode is enabled:
 - Global link:syntax.html#aliases[aliases] are not substituted.
 - Nested commands in a link:syntax.html#compound[compound command] must not be
   empty.
-- Words expanded in a link:syntax.html#for[for loop] are assigned as a global
-  variable rather than a local. The variable must have a portable (ASCII-only)
-  name.
+- The link:syntax.html#for[for loop] iteration variable is created as global,
+  regardless of the link:_set.html#so-forlocal[forlocal] shell option.
+  The variable must have a portable (ASCII-only) name.
 - The first pattern in a link:syntax.html#case[case command] cannot be +esac+.
 - The +!+ keyword cannot be followed by +(+ without any whitespaces
   in-between.
diff --git a/doc/syntax.txt b/doc/syntax.txt
index f9ab35f5..678a7049 100644
--- a/doc/syntax.txt
+++ b/doc/syntax.txt
@@ -340,10 +340,14 @@ order the words were expanded):
 . Assign the word to the variable whose name is {{varname}}.
 . Execute the {{command}}s.
 
-Each word is assigned as a link:exec.html#localvar[local variable] except in
-the POSIXly-correct mode.
-If the expansion of the {{word}}s yielded no words as a result, the
-{{command}}s are not executed at all.
+By default, if a for loop is executed within a function, {{varname}} is
+created as a link:exec.html#localvar[local variable], even if it already
+exists globally. Turning off the link:_set.html#so-forlocal[forlocal] shell
+option or enabling the link:posix.html[POSIXly-correct mode] mode will
+disable this behavior.
+
+If the expansion of the {{word}}s yields no words, no variable is created
+and the {{command}}s are not executed at all.
 
 The exit status of a for loop is that of the last executed {{command}}. The
 exit status is zero if the {{command}}s are not empty and not executed at all.
diff --git a/exec.c b/exec.c
index 4cfc446a..9fbd5feb 100644
--- a/exec.c
+++ b/exec.c
@@ -447,7 +447,9 @@ void exec_for(const command_T *c, bool finally_exit)
     int i;
     for (i = 0; i < count; i++) {
 	if (!set_variable(c->c_forname, words[i],
-		    posixly_correct ? SCOPE_GLOBAL : SCOPE_LOCAL, false)) {
+		    shopt_forlocal && !posixly_correct ?
+			SCOPE_LOCAL : SCOPE_GLOBAL,
+		    false)) {
 	    laststatus = Exit_ASSGNERR;
 	    goto done;
 	}
diff --git a/option.c b/option.c
index 8aab9d1d..eb68d218 100644
--- a/option.c
+++ b/option.c
@@ -89,6 +89,8 @@ bool shopt_allexport = false;
 /* If set, when a function is defined, all the commands in the function
  * are hashed. Corresponds to the -h/--hashondef option. */
 bool shopt_hashondef = false;
+/* If set, the 'for' loop iteration variable will be made local. */
+bool shopt_forlocal = true;
 
 /* If set, when a command returns a non-zero status, the shell exits.
  * Corresponds to the -e/--errexit option. */
@@ -223,6 +225,7 @@ static const struct option_T shell_options[] = {
     { 0,    0,    L"errreturn",      &shopt_errreturn,      true, },
     { 0,    L'n', L"exec",           &shopt_exec,           true, },
     { 0,    0,    L"extendedglob",   &shopt_extendedglob,   true, },
+    { 0,    0,    L"forlocal",       &shopt_forlocal,       true, },
     { 0,    L'f', L"glob",           &shopt_glob,           true, },
     { L'h', 0,    L"hashondef",      &shopt_hashondef,      true, },
 #if YASH_ENABLE_HISTORY
diff --git a/option.h b/option.h
index 81cf18c8..308b9f14 100644
--- a/option.h
+++ b/option.h
@@ -41,7 +41,7 @@ extern _Bool is_interactive, is_interactive_now;
 extern _Bool shopt_cmdline, shopt_stdin;
 extern _Bool do_job_control, shopt_notify, shopt_notifyle,
        shopt_curasync, shopt_curbg, shopt_curstop;
-extern _Bool shopt_allexport, shopt_hashondef;
+extern _Bool shopt_allexport, shopt_hashondef, shopt_forlocal;
 extern _Bool shopt_errexit, shopt_errreturn, shopt_pipefail, shopt_unset,
        shopt_exec, shopt_ignoreeof, shopt_verbose, shopt_xtrace;
 extern _Bool shopt_traceall;
diff --git a/tests/for-p.tst b/tests/for-p.tst
index 90a72bce..fd76f4c0 100644
--- a/tests/for-p.tst
+++ b/tests/for-p.tst
@@ -163,4 +163,13 @@ b 2
 c 3
 __OUT__
 
+test_o 'iteration variable is global'
+unset -v i
+fn() { for i in a b c; do : ; done; }
+fn
+echo "${i-UNSET}"
+__IN__
+c
+__OUT__
+
 # vim: set ft=sh ts=8 sts=4 sw=4 noet:
diff --git a/tests/for-y.tst b/tests/for-y.tst
index 4a94205a..a62652a4 100644
--- a/tests/for-y.tst
+++ b/tests/for-y.tst
@@ -336,4 +336,23 @@ for v in 1; do
 done
 __IN__
 
+test_oE 'iteration variable is local'
+unset -v i
+fn() { for i in a b c; do : ; done; }
+fn
+echo "${i-UNSET}"
+__IN__
+UNSET
+__OUT__
+
+test_oE 'noforlocal: iteration variable is global'
+set -o noforlocal
+unset -v i
+fn() { for i in a b c; do : ; done; }
+fn
+echo "${i-UNSET}"
+__IN__
+c
+__OUT__
+
 # vim: set ft=sh ts=8 sts=4 sw=4 noet:
diff --git a/tests/help-y.tst b/tests/help-y.tst
index 1398d80f..3fd66563 100644
--- a/tests/help-y.tst
+++ b/tests/help-y.tst
@@ -771,6 +771,7 @@ Options:
 	         -o errreturn
 	+n       -o exec
 	         -o extendedglob
+	         -o forlocal
 	+f       -o glob
 	-h       -o hashondef
 	         -o histspace
diff --git a/tests/set-y.tst b/tests/set-y.tst
index 9a33760d..0012ad28 100644
--- a/tests/set-y.tst
+++ b/tests/set-y.tst
@@ -411,6 +411,7 @@ errexit         off
 errreturn       off
 exec            on
 extendedglob    off
+forlocal        on
 glob            on
 hashondef       off
 ignoreeof       off
@@ -465,6 +466,7 @@ set +o errexit
 set +o errreturn
 set -o exec
 set +o extendedglob
+set -o forlocal
 set -o glob
 set +o hashondef
 set +o ignoreeof
diff --git a/tests/startup-y.tst b/tests/startup-y.tst
index 0b394250..726a9c0c 100644
--- a/tests/startup-y.tst
+++ b/tests/startup-y.tst
@@ -553,6 +553,7 @@ Options:
 	         -o errreturn
 	+n       -o exec
 	         -o extendedglob
+	         -o forlocal
 	+f       -o glob
 	-h       -o hashondef
 	         -o histspace
@@ -610,6 +611,7 @@ Options:
 	         -o errreturn
 	+n       -o exec
 	         -o extendedglob
+	         -o forlocal
 	+f       -o glob
 	-h       -o hashondef
 	         -o histspace