Browse Source

+ nested exit support

git-svn-id: trunk@23309 -
florian 12 years ago
parent
commit
fce9e953b4

+ 2 - 1
.gitattributes

@@ -11099,7 +11099,8 @@ tests/test/tmaclocalprocparam4e.pp svneol=native#text/plain
 tests/test/tmaclocalprocparam4f.pp svneol=native#text/plain
 tests/test/tmaclocalprocparam4f.pp svneol=native#text/plain
 tests/test/tmaclocalprocparam4g.pp svneol=native#text/plain
 tests/test/tmaclocalprocparam4g.pp svneol=native#text/plain
 tests/test/tmaclocalprocparam4h.pp svneol=native#text/plain
 tests/test/tmaclocalprocparam4h.pp svneol=native#text/plain
-tests/test/tmacnonlocalexit.pp svneol=native#text/plain
+tests/test/tmacnonlocalexit1.pp svneol=native#text/plain
+tests/test/tmacnonlocalexit2.pp svneol=native#text/pascal
 tests/test/tmacnonlocalgoto.pp svneol=native#text/plain
 tests/test/tmacnonlocalgoto.pp svneol=native#text/plain
 tests/test/tmacpas1.pp svneol=native#text/plain
 tests/test/tmacpas1.pp svneol=native#text/plain
 tests/test/tmacpas2.pp svneol=native#text/plain
 tests/test/tmacpas2.pp svneol=native#text/plain

+ 3 - 1
compiler/globtype.pas

@@ -564,7 +564,9 @@ interface
          { subroutine contains interprocedural gotos }
          { subroutine contains interprocedural gotos }
          pi_has_global_goto,
          pi_has_global_goto,
          { subroutine contains inherited call }
          { subroutine contains inherited call }
-         pi_has_inherited
+         pi_has_inherited,
+         { subroutine has nested exit }
+         pi_has_nested_exit
        );
        );
        tprocinfoflags=set of tprocinfoflag;
        tprocinfoflags=set of tprocinfoflag;
 
 

+ 2 - 2
compiler/msg/errore.msg

@@ -1075,8 +1075,8 @@ parser_e_invalid_qualifier=03205_E_Illegal qualifier
 parser_e_upper_lower_than_lower=03206_E_High range limit < low range limit
 parser_e_upper_lower_than_lower=03206_E_High range limit < low range limit
 % You are declaring a subrange, and the high limit is less than the low limit of
 % You are declaring a subrange, and the high limit is less than the low limit of
 % the range.
 % the range.
-parser_e_macpas_exit_wrong_param=03207_E_Exit's parameter must be the name of the procedure it is used in
-% Non local exit is not allowed. This error occurs only in mode MacPas.
+parser_e_macpas_exit_wrong_param=03207_E_Exit's parameter must be the name of the procedure it is used in or of a surrounding procedure
+% The parameter of a exit call in macpas mode must be either the name of the current subroutine or of a surrounding one
 parser_e_illegal_assignment_to_count_var=03208_E_Illegal assignment to for-loop variable "$1"
 parser_e_illegal_assignment_to_count_var=03208_E_Illegal assignment to for-loop variable "$1"
 % The type of a \var{for} loop variable must be an ordinal type.
 % The type of a \var{for} loop variable must be an ordinal type.
 % Loop variables cannot be reals or strings. You also cannot assign values to
 % Loop variables cannot be reals or strings. You also cannot assign values to

+ 1 - 1
compiler/msgidx.inc

@@ -963,7 +963,7 @@ const
   option_info=11024;
   option_info=11024;
   option_help_pages=11025;
   option_help_pages=11025;
 
 
-  MsgTxtSize = 68063;
+  MsgTxtSize = 68093;
 
 
   MsgIdxMax : array[1..20] of longint=(
   MsgIdxMax : array[1..20] of longint=(
     26,93,328,120,87,56,126,26,202,63,
     26,93,328,120,87,56,126,26,202,63,

File diff suppressed because it is too large
+ 282 - 284
compiler/msgtxt.inc


+ 4 - 2
compiler/nflw.pas

@@ -1718,8 +1718,10 @@ implementation
               { generated by the optimizer? }
               { generated by the optimizer? }
                not(assigned(labelsym.owner))) then
                not(assigned(labelsym.owner))) then
               labelnode:=tlabelnode(labelsym.code)
               labelnode:=tlabelnode(labelsym.code)
-            else if (m_non_local_goto in current_settings.modeswitches) and
-              assigned(labelsym.owner) then
+            else if ((m_non_local_goto in current_settings.modeswitches) and
+              assigned(labelsym.owner)) or
+              { nested exits don't need the non local goto switch }
+              (labelsym.realname='$nestedexit') then
               begin
               begin
                 if current_procinfo.procdef.parast.symtablelevel>labelsym.owner.symtablelevel then
                 if current_procinfo.procdef.parast.symtablelevel>labelsym.owner.symtablelevel then
                   begin
                   begin

+ 40 - 3
compiler/pexpr.pas

@@ -226,6 +226,7 @@ implementation
          hdef  : tdef;
          hdef  : tdef;
          temp  : ttempcreatenode;
          temp  : ttempcreatenode;
          newstatement : tstatementnode;
          newstatement : tstatementnode;
+         procinfo : tprocinfo;
        begin
        begin
          { Properties are not allowed, because the write can
          { Properties are not allowed, because the write can
            be different from the read }
            be different from the read }
@@ -269,6 +270,7 @@ implementation
         err,
         err,
         prev_in_args : boolean;
         prev_in_args : boolean;
         def : tdef;
         def : tdef;
+        exit_procinfo: tprocinfo;
       begin
       begin
         prev_in_args:=in_args;
         prev_in_args:=in_args;
         case l of
         case l of
@@ -298,6 +300,7 @@ implementation
 
 
           in_exit :
           in_exit :
             begin
             begin
+              statement_syssym:=nil;
               if try_to_consume(_LKLAMMER) then
               if try_to_consume(_LKLAMMER) then
                 begin
                 begin
                   if not (m_mac in current_settings.modeswitches) then
                   if not (m_mac in current_settings.modeswitches) then
@@ -321,8 +324,40 @@ implementation
                     end
                     end
                   else
                   else
                     begin
                     begin
-                      if not (current_procinfo.procdef.procsym.name = pattern) then
-                        Message(parser_e_macpas_exit_wrong_param);
+                      { non local exit ? }
+                      if current_procinfo.procdef.procsym.name<>pattern then
+                        begin
+                          exit_procinfo:=current_procinfo.parent;
+                          while assigned(exit_procinfo) do
+                            begin
+                              if exit_procinfo.procdef.procsym.name=pattern then
+                                break;
+                              exit_procinfo:=exit_procinfo.parent;
+                            end;
+                          if assigned(exit_procinfo) then
+                            begin
+                              if not(assigned(exit_procinfo.nestedexitlabel)) then
+                                begin
+                                  include(exit_procinfo.flags,pi_has_nested_exit);
+                                  exclude(exit_procinfo.procdef.procoptions,po_inline);
+
+                                  exit_procinfo.nestedexitlabel:=tlabelsym.create('$nestedexit');
+
+                                  { the compiler is responsible to define this label }
+                                  exit_procinfo.nestedexitlabel.defined:=true;
+                                  exit_procinfo.nestedexitlabel.used:=true;
+
+                                  exit_procinfo.nestedexitlabel.jumpbuf:=tlocalvarsym.create('LABEL$_'+exit_procinfo.nestedexitlabel.name,vs_value,rec_jmp_buf,[]);
+                                  exit_procinfo.procdef.localst.insert(exit_procinfo.nestedexitlabel);
+                                  exit_procinfo.procdef.localst.insert(exit_procinfo.nestedexitlabel.jumpbuf);
+                                end;
+
+                              statement_syssym:=cgotonode.create(exit_procinfo.nestedexitlabel);
+                              tgotonode(statement_syssym).labelsym:=exit_procinfo.nestedexitlabel;
+                            end
+                          else
+                            Message(parser_e_macpas_exit_wrong_param);
+                        end;
                       consume(_ID);
                       consume(_ID);
                       consume(_RKLAMMER);
                       consume(_RKLAMMER);
                       p1:=nil;
                       p1:=nil;
@@ -330,7 +365,8 @@ implementation
                 end
                 end
               else
               else
                 p1:=nil;
                 p1:=nil;
-              statement_syssym:=cexitnode.create(p1);
+              if not assigned(statement_syssym) then
+                statement_syssym:=cexitnode.create(p1);
             end;
             end;
 
 
           in_break :
           in_break :
@@ -732,6 +768,7 @@ implementation
                   statement_syssym:=cerrornode.create;
                   statement_syssym:=cerrornode.create;
                 end;
                 end;
             end;
             end;
+
           in_length_x:
           in_length_x:
             begin
             begin
               consume(_LKLAMMER);
               consume(_LKLAMMER);

+ 3 - 0
compiler/procinfo.pas

@@ -112,6 +112,9 @@ unit procinfo;
           { label to leave the sub routine }
           { label to leave the sub routine }
           CurrExitLabel : tasmlabel;
           CurrExitLabel : tasmlabel;
 
 
+          { label for nested exits }
+          nestedexitlabel : tlabelsym;
+
           { The code for the routine itself, excluding entry and
           { The code for the routine itself, excluding entry and
             exit code. This is a linked list of tai classes.
             exit code. This is a linked list of tai classes.
           }
           }

+ 8 - 4
compiler/pstatmnt.pas

@@ -1249,11 +1249,15 @@ implementation
              if p.nodetype in [vecn,derefn,typeconvn,subscriptn,loadn] then
              if p.nodetype in [vecn,derefn,typeconvn,subscriptn,loadn] then
                maybe_call_procvar(p,false);
                maybe_call_procvar(p,false);
 
 
-             { blockn support because a read/write is changed into a blocknode }
-             { with a separate statement for each read/write operation (JM)    }
-             { the same is true for val() if the third parameter is not 32 bit }
+             { blockn support because a read/write is changed into a blocknode
+               with a separate statement for each read/write operation (JM)
+               the same is true for val() if the third parameter is not 32 bit
+
+               goto nodes are created by the compiler for non local exit statements, so
+               include them as well
+             }
              if not(p.nodetype in [nothingn,errorn,calln,ifn,assignn,breakn,inlinen,
              if not(p.nodetype in [nothingn,errorn,calln,ifn,assignn,breakn,inlinen,
-                                   continuen,labeln,blockn,exitn]) or
+                                   continuen,labeln,blockn,exitn,goton]) or
                 ((p.nodetype=inlinen) and
                 ((p.nodetype=inlinen) and
                  not is_void(p.resultdef)) or
                  not is_void(p.resultdef)) or
                 ((p.nodetype=calln) and
                 ((p.nodetype=calln) and

+ 8 - 0
compiler/psub.pas

@@ -144,6 +144,12 @@ implementation
             Message(parser_h_inlining_disabled);
             Message(parser_h_inlining_disabled);
             exit;
             exit;
           end;
           end;
+        if pi_has_nested_exit in current_procinfo.flags then
+          begin
+            Message1(parser_h_not_supported_for_inline,'nested exit');
+            Message(parser_h_inlining_disabled);
+            exit;
+          end;
         { the compiler cannot handle inherited in inlined subroutines because
         { the compiler cannot handle inherited in inlined subroutines because
           it tries to search for self in the symtable, however, the symtable
           it tries to search for self in the symtable, however, the symtable
           is not available }
           is not available }
@@ -861,6 +867,8 @@ implementation
             maybe_add_constructor_wrapper(code,
             maybe_add_constructor_wrapper(code,
               cs_implicit_exceptions in current_settings.moduleswitches);
               cs_implicit_exceptions in current_settings.moduleswitches);
             addstatement(newstatement,code);
             addstatement(newstatement,code);
+            if assigned(nestedexitlabel) then
+              addstatement(newstatement,clabelnode.create(cnothingnode.create,nestedexitlabel));
             addstatement(newstatement,exitlabel_asmnode);
             addstatement(newstatement,exitlabel_asmnode);
             addstatement(newstatement,bodyexitcode);
             addstatement(newstatement,bodyexitcode);
             if not is_constructor then
             if not is_constructor then

+ 3 - 1
compiler/utils/ppudump.pp

@@ -1062,7 +1062,9 @@ const
          (mask:pi_has_global_goto;
          (mask:pi_has_global_goto;
          str:' subroutine contains interprocedural goto '),
          str:' subroutine contains interprocedural goto '),
          (mask:pi_has_inherited;
          (mask:pi_has_inherited;
-         str:' subroutine contains inherited call ')
+         str:' subroutine contains inherited call '),
+         (mask:pi_has_nested_exit;
+         str:' subroutine contains a nested subroutine which calls the exit of the current one ')
   );
   );
 var
 var
   procinfooptions : tprocinfoflags;
   procinfooptions : tprocinfoflags;

+ 0 - 0
tests/test/tmacnonlocalexit.pp → tests/test/tmacnonlocalexit1.pp


+ 41 - 0
tests/test/tmacnonlocalexit2.pp

@@ -0,0 +1,41 @@
+{ %fail }
+program tmacnonlocalexit2;
+{$MODE MACPAS}
+
+	var
+		failed: Boolean;
+
+	procedure Global;
+
+                procedure AnotherLocal;
+                  begin
+                  end;
+
+
+		procedure Local;
+		begin
+			Exit(AnotherLocal);
+			failed := true;
+		end;
+
+	begin
+		Local;
+		failed := true;
+	end;
+
+
+begin
+	failed := false;
+
+	Global;
+
+	if failed then
+		writeln('Failed')
+	else
+		writeln('Succeded');
+
+  {$IFC NOT UNDEFINED FPC}
+	if failed then
+		Halt(1);
+  {$ENDC}
+end.

Some files were not shown because too many files changed in this diff