changeset 25478:a06983fe83a5 stable

maybe preserve local value when declaring variable global (bug #54052) * pt-eval.cc (tree_evaluator::visit_decl_elt): In global declaration, if local value is defined but global is not, then preserve global value. If global value is already defined, override local value with global value. Either way, warn about variable already being defined. * test/global.tst: New tests.
author John W. Eaton <jwe@octave.org>
date Fri, 15 Jun 2018 15:35:45 -0400
parents 9771111f04f4
children 594eeec64f14 0d7a89bec20e
files libinterp/parse-tree/pt-eval.cc test/global.tst
diffstat 2 files changed, 83 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/parse-tree/pt-eval.cc	Wed Jun 13 16:21:58 2018 -0700
+++ b/libinterp/parse-tree/pt-eval.cc	Fri Jun 15 15:35:45 2018 -0400
@@ -727,11 +727,51 @@
       {
         if (elt.is_global ())
           {
+            std::string name = id->name ();
+
             symbol_table& symtab = m_interpreter.get_symbol_table ();
 
-            symbol_record global_sym = symtab.find_global_symbol (id->name ());
-
-            id->link_to_global (symtab.global_scope (), global_sym);
+            symbol_scope global_scope = symtab.global_scope ();
+
+            symbol_record global_sr = global_scope.find_symbol (name);
+
+            // FIXME: Hmmm.  Seems like this should happen automatically
+            // for symbols coming from the global scope...
+            global_sr.mark_global ();
+
+            symbol_scope scope = symtab.current_scope ();
+
+            if (! scope.is_global (name))
+              {
+                octave_value val = scope.varval (name);
+
+                bool local_val_is_defined = val.is_defined ();
+
+                if (local_val_is_defined)
+                  {
+                    warning_with_id ("Octave:global-from-local",
+                                     "global: '%s' is defined in the current scope",
+                                     name.c_str ());
+                    warning_with_id ("Octave:global-from-local",
+                                     "global: in a future version, global variables must be declared before use");
+
+                    // If the symbol is defined in the local but not the
+                    // global scope, then use the local value as the
+                    // initial value.  This value will also override any
+                    // initializer in the global statement.
+                    octave_value global_val = global_scope.varval (name);
+
+                    if (! global_val.is_defined ())
+                      {
+                        warning_with_id ("Octave:global-from-local",
+                                         "global: global value overrides local value");
+
+                        global_scope.assign (name, val);
+                      }
+                  }
+
+                id->link_to_global (global_scope, global_sr);
+              }
           }
         else if (elt.is_persistent ())
           id->mark_persistent ();
--- a/test/global.tst	Wed Jun 13 16:21:58 2018 -0700
+++ b/test/global.tst	Fri Jun 15 15:35:45 2018 -0400
@@ -80,3 +80,43 @@
 %! f;
 %! clear H;
 %! g;
+
+%!function r = f ()
+%!  x = 1;
+%!  global x;
+%!  r = x;
+%!endfunction
+%!test
+%! warning ("off", "Octave:global-from-local", "local");
+%! clear global x
+%! global x
+%! x = 0;
+%! assert (f (), 0);
+%! global x
+%! assert (x, 0);
+%!test
+%! warning ("off", "Octave:global-from-local", "local");
+%! clear global x
+%! assert (f (), 1);
+%! global x
+%! assert (x, 1);
+
+%!function r = f ()
+%!  x = 1;
+%!  global x = 3;
+%!  r = x;
+%!endfunction
+%!test
+%! warning ("off", "Octave:global-from-local", "local");
+%! clear global x
+%! global x
+%! x = 0;
+%! assert (f (), 0);
+%! global x
+%! assert (x, 0);
+%!test
+%! warning ("off", "Octave:global-from-local", "local");
+%! clear global x
+%! assert (f (), 1);
+%! global x
+%! assert (x, 1);