In mcs:
authorRaja R Harinath <harinath@hurrynot.org>
Thu, 18 May 2006 15:34:54 +0000 (15:34 -0000)
committerRaja R Harinath <harinath@hurrynot.org>
Thu, 18 May 2006 15:34:54 +0000 (15:34 -0000)
Fix #77601
* statement.cs (Goto.Resolve): Move responsibility for resolving
'goto' to FlowBranching.AddGotoOrigin.
(Goto.SetResolvedTarget): New.  Callback to set the
LabeledStatement that's the target of the goto.
(Goto.DoEmit): Use Leave instead of Br when crossing an
unwind-protect boundary.
* flowanalysis.cs (FlowBranching.AddGotoOrigin): Rename from
LookupLabel and adjust to new semantics.
(FlowBranchingToplevel.AddGotoOrigin): Likewise.
(FlowBranchingBlock.AddGotoOrigin): Likewise. Use
Goto.SetResolvedTarget to update target.
(FlowBranchingLabeled.AddGotoOrigin): Likewise.
(FlowBranchingException.AddGotoOrigin): Rewrite to be similar to
AddBreakOrigin & co.  Delay propagation until ...
(FlowBranchingException.Merge): ... this.

In gmcs:
Fix #77601
* statement.cs (Goto.Resolve): Move responsibility for resolving
'goto' to FlowBranching.AddGotoOrigin.
(Goto.SetResolvedTarget): New.  Callback to set the
LabeledStatement that's the target of the goto.
(Goto.DoEmit): Use Leave instead of Br when crossing an
unwind-protect boundary.
* flowanalysis.cs (FlowBranching.AddGotoOrigin): Rename from
LookupLabel and adjust to new semantics.
(FlowBranchingToplevel.AddGotoOrigin): Likewise.
(FlowBranchingBlock.AddGotoOrigin): Likewise. Use
Goto.SetResolvedTarget to update target.
(FlowBranchingLabeled.AddGotoOrigin): Likewise.
(FlowBranchingException.AddGotoOrigin): Rewrite to be similar to
AddBreakOrigin & co.  Delay propagation until ...
(FlowBranchingException.Merge): ... this.

In tests:
* test-518.cs: New test based on #77601.

svn path=/trunk/mcs/; revision=60827

mcs/gmcs/ChangeLog
mcs/gmcs/flowanalysis.cs
mcs/gmcs/statement.cs
mcs/mcs/ChangeLog
mcs/mcs/flowanalysis.cs
mcs/mcs/statement.cs
mcs/tests/ChangeLog
mcs/tests/test-518.cs [new file with mode: 0644]

index 057939b9414fabd9d86c461753dd711da4794247..37ffc302d2a19f02136ac24a9f0039d8c2beb390 100644 (file)
@@ -1,5 +1,22 @@
 2006-05-18  Raja R Harinath  <rharinath@novell.com>
 
+       Fix #77601
+       * statement.cs (Goto.Resolve): Move responsibility for resolving
+       'goto' to FlowBranching.AddGotoOrigin.
+       (Goto.SetResolvedTarget): New.  Callback to set the
+       LabeledStatement that's the target of the goto.
+       (Goto.DoEmit): Use Leave instead of Br when crossing an
+       unwind-protect boundary.
+       * flowanalysis.cs (FlowBranching.AddGotoOrigin): Rename from
+       LookupLabel and adjust to new semantics.
+       (FlowBranchingToplevel.AddGotoOrigin): Likewise.
+       (FlowBranchingBlock.AddGotoOrigin): Likewise. Use
+       Goto.SetResolvedTarget to update target.
+       (FlowBranchingLabeled.AddGotoOrigin): Likewise.
+       (FlowBranchingException.AddGotoOrigin): Rewrite to be similar to
+       AddBreakOrigin & co.  Delay propagation until ...
+       (FlowBranchingException.Merge): ... this.
+
        * statement.cs (Block.Resolve): Always depend on flow-branching to
        determine unreachability.  Kill workaround that originally emitted
        only one statement after an "unreachable" label (see infloop in
index c91e3f3bdec4b97fda9f24abd1a9ee07ba6ebd6e..68cae97de22b601d9e699a396c326ea2beb85a49 100644 (file)
@@ -618,11 +618,6 @@ namespace Mono.CSharp
 
                protected abstract void AddSibling (UsageVector uv);
 
-               public virtual LabeledStatement LookupLabel (string name, Location loc)
-               {
-                       return Parent.LookupLabel (name, loc);
-               }
-
                protected abstract UsageVector Merge ();
 
                // <summary>
@@ -661,6 +656,12 @@ namespace Mono.CSharp
                        return Parent.AddReturnOrigin (vector, loc);
                }
 
+               // returns true if we crossed an unwind-protected region (try/catch/finally, lock, using, ...)
+               public virtual bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
+               {
+                       return Parent.AddGotoOrigin (vector, goto_stmt);
+               }
+
                public virtual void StealFinallyClauses (ref ArrayList list)
                {
                        Parent.StealFinallyClauses (ref list);
@@ -733,14 +734,16 @@ namespace Mono.CSharp
                        sibling_list = sibling;
                }
 
-               public override LabeledStatement LookupLabel (string name, Location loc)
+               public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
                {
-                       LabeledStatement stmt = Block == null ? null : Block.LookupLabel (name);
+                       LabeledStatement stmt = Block == null ? null : Block.LookupLabel (goto_stmt.Target);
                        if (stmt == null)
-                               return Parent.LookupLabel (name, loc);
+                               return Parent.AddGotoOrigin (vector, goto_stmt);
 
-                       stmt.AddReference ();
-                       return stmt;
+                       // forward jump
+                       goto_stmt.SetResolvedTarget (stmt);
+                       stmt.AddUsageVector (vector);
+                       return false;
                }
 
                protected override UsageVector Merge ()
@@ -802,7 +805,6 @@ namespace Mono.CSharp
 
        public class FlowBranchingLabeled : FlowBranchingBlock
        {
-               bool unreachable, backward_jump;
                LabeledStatement stmt;
                UsageVector actual;
 
@@ -812,34 +814,30 @@ namespace Mono.CSharp
                        this.stmt = stmt;
                        CurrentUsageVector.MergeOrigins (stmt.JumpOrigins);
                        actual = CurrentUsageVector.Clone ();
-                       unreachable = actual.Reachability.IsUnreachable;
 
                        // stand-in for backward jumps
                        CurrentUsageVector.Reachability.Meet (Reachability.Always ());
                }
 
-               public override LabeledStatement LookupLabel (string name, Location loc)
+               public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
                {
-                       if (name != stmt.Name)
-                               return Parent.LookupLabel (name, loc);
+                       if (goto_stmt.Target != stmt.Name)
+                               return Parent.AddGotoOrigin (vector, goto_stmt);
 
-                       unreachable = false;
-                       backward_jump = true;
+                       // backward jump
+                       goto_stmt.SetResolvedTarget (stmt);
+                       actual.MergeOrigins (vector.Clone ());
 
-                       stmt.AddReference ();
-                       return stmt;
+                       return false;
                }
 
                protected override UsageVector Merge ()
                {
                        UsageVector vector = base.Merge ();
 
-                       if (unreachable)
+                       if (actual.Reachability.IsUnreachable)
                                Report.Warning (162, 2, stmt.loc, "Unreachable code detected");
 
-                       if (backward_jump)
-                               return vector;
-
                        actual.MergeChild (vector, false);
                        return actual;
                }
@@ -899,22 +897,23 @@ namespace Mono.CSharp
                        // nothing to do
                }
 
-               public override LabeledStatement LookupLabel (string name, Location loc)
+               public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
                {
+                       string name = goto_stmt.Target;
                        LabeledStatement s = Block.LookupLabel (name);
                        if (s != null)
                                throw new InternalErrorException ("Shouldn't get here");
 
-                       if (Parent != null) {
-                               s = Parent.LookupLabel (name, loc);
-                               if (s != null) {
-                                       Report.Error (1632, loc, "Control cannot leave the body of an anonymous method");
-                                       return null;
-                               }
+                       if (Parent == null) {
+                               Report.Error (159, goto_stmt.loc, "No such label `{0}' in this scope", name);
+                               return false;
                        }
 
-                       Report.Error (159, loc, "No such label `{0}' in this scope", name);
-                       return null;
+                       int errors = Report.Errors;
+                       Parent.AddGotoOrigin (vector, goto_stmt);
+                       if (errors == Report.Errors)
+                               Report.Error (1632, goto_stmt.loc, "Control cannot leave the body of an anonymous method");
+                       return false;
                }
 
                public Reachability End ()
@@ -940,6 +939,20 @@ namespace Mono.CSharp
                UsageVector break_origins;
                UsageVector continue_origins;
                UsageVector return_origins;
+               GotoOrigin goto_origins;
+
+               class GotoOrigin {
+                       public GotoOrigin Next;
+                       public Goto GotoStmt;
+                       public UsageVector Vector;
+
+                       public GotoOrigin (UsageVector vector, Goto goto_stmt, GotoOrigin next)
+                       {
+                               Vector = vector;
+                               GotoStmt = goto_stmt;
+                               Next = next;
+                       }
+               }
 
                bool emit_finally;
 
@@ -1023,6 +1036,19 @@ namespace Mono.CSharp
                        return true;
                }
 
+               public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
+               {
+                       LabeledStatement s = current_vector.Block == null ? null : current_vector.Block.LookupLabel (goto_stmt.Target);
+                       if (s != null)
+                               throw new InternalErrorException ("Shouldn't get here");
+
+                       if (finally_vector != null)
+                               Report.Error (157, goto_stmt.loc, "Control cannot leave the body of a finally clause");
+                       else
+                               goto_origins = new GotoOrigin (vector.Clone (), goto_stmt, goto_origins);
+                       return true;
+               }
+
                public override void StealFinallyClauses (ref ArrayList list)
                {
                        if (list == null)
@@ -1036,23 +1062,6 @@ namespace Mono.CSharp
                        get { return emit_finally; }
                }
 
-               public override LabeledStatement LookupLabel (string name, Location loc)
-               {
-                       if (current_vector.Block == null)
-                               return base.LookupLabel (name, loc);
-
-                       LabeledStatement s = current_vector.Block.LookupLabel (name);
-                       if (s != null)
-                               return s;
-
-                       if (finally_vector != null) {
-                               Report.Error (157, loc, "Control cannot leave the body of a finally clause");
-                               return null;
-                       }
-
-                       return base.LookupLabel (name, loc);
-               }
-
                protected override UsageVector Merge ()
                {
                        Report.Debug (2, "  MERGING TRY/CATCH", Name);
@@ -1083,6 +1092,13 @@ namespace Mono.CSharp
                                        Parent.AddReturnOrigin (origin, origin.Location);
                        }
 
+                       for (GotoOrigin origin = goto_origins; origin != null; origin = origin.Next) {
+                               if (finally_vector != null)
+                                       origin.Vector.MergeChild (finally_vector, false);
+                               if (!origin.Vector.Reachability.IsUnreachable)
+                                       Parent.AddGotoOrigin (origin.Vector, origin.GotoStmt);
+                       }
+
                        return vector;
                }
        }
index 2200803914485dfcfa30a3c60767bfe24849ae0d..e0029fd1bf560bfd62ca0bc10147ecf015ad470c 100644 (file)
@@ -582,7 +582,7 @@ namespace Mono.CSharp {
                        loc = l;
                }
 
-               bool in_exc;
+               bool unwind_protect;
 
                public override bool Resolve (EmitContext ec)
                {
@@ -624,8 +624,8 @@ namespace Mono.CSharp {
                        }
 
                        int errors = Report.Errors;
-                       in_exc = ec.CurrentBranching.AddReturnOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
-                       if (in_exc)
+                       unwind_protect = ec.CurrentBranching.AddReturnOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
+                       if (unwind_protect)
                                ec.NeedReturnLabel ();
                        ec.CurrentBranching.CurrentUsageVector.Return ();
                        return errors == Report.Errors;
@@ -636,11 +636,11 @@ namespace Mono.CSharp {
                        if (Expr != null) {
                                Expr.Emit (ec);
 
-                               if (in_exc)
+                               if (unwind_protect)
                                        ec.ig.Emit (OpCodes.Stloc, ec.TemporaryReturn ());
                        }
 
-                       if (in_exc)
+                       if (unwind_protect)
                                ec.ig.Emit (OpCodes.Leave, ec.ReturnLabel);
                        else
                                ec.ig.Emit (OpCodes.Ret);
@@ -650,20 +650,14 @@ namespace Mono.CSharp {
        public class Goto : Statement {
                string target;
                LabeledStatement label;
+               bool unwind_protect;
                
                public override bool Resolve (EmitContext ec)
                {
-                       label = ec.CurrentBranching.LookupLabel (target, loc);
-                       if (label == null)
-                               return false;
-
-                       // If this is a forward goto.
-                       if (!label.IsDefined)
-                               label.AddUsageVector (ec.CurrentBranching.CurrentUsageVector);
-
+                       int errors = Report.Errors;
+                       unwind_protect = ec.CurrentBranching.AddGotoOrigin (ec.CurrentBranching.CurrentUsageVector, this);
                        ec.CurrentBranching.CurrentUsageVector.Goto ();
-
-                       return true;
+                       return errors == Report.Errors;
                }
                
                public Goto (string label, Location l)
@@ -676,10 +670,18 @@ namespace Mono.CSharp {
                        get { return target; }
                }
 
+               public void SetResolvedTarget (LabeledStatement label)
+               {
+                       this.label = label;
+                       label.AddReference ();
+               }
+
                protected override void DoEmit (EmitContext ec)
                {
+                       if (label == null)
+                               throw new InternalErrorException ("goto emitted before target resolved");
                        Label l = label.LabelTarget (ec);
-                       ec.ig.Emit (OpCodes.Br, l);
+                       ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, l);
                }
        }
 
@@ -910,19 +912,19 @@ namespace Mono.CSharp {
                        loc = l;
                }
 
-               bool crossing_exc;
+               bool unwind_protect;
 
                public override bool Resolve (EmitContext ec)
                {
                        int errors = Report.Errors;
-                       crossing_exc = ec.CurrentBranching.AddBreakOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
+                       unwind_protect = ec.CurrentBranching.AddBreakOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
                        ec.CurrentBranching.CurrentUsageVector.Goto ();
                        return errors == Report.Errors;
                }
 
                protected override void DoEmit (EmitContext ec)
                {
-                       ec.ig.Emit (crossing_exc ? OpCodes.Leave : OpCodes.Br, ec.LoopEnd);
+                       ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopEnd);
                }
        }
 
@@ -933,19 +935,19 @@ namespace Mono.CSharp {
                        loc = l;
                }
 
-               bool crossing_exc;
+               bool unwind_protect;
 
                public override bool Resolve (EmitContext ec)
                {
                        int errors = Report.Errors;
-                       crossing_exc = ec.CurrentBranching.AddContinueOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
+                       unwind_protect = ec.CurrentBranching.AddContinueOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
                        ec.CurrentBranching.CurrentUsageVector.Goto ();
                        return errors == Report.Errors;
                }
 
                protected override void DoEmit (EmitContext ec)
                {
-                       ec.ig.Emit (crossing_exc ? OpCodes.Leave : OpCodes.Br, ec.LoopBegin);
+                       ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopBegin);
                }
        }
 
index 57936aabcf95606eab19a57eba90064fdbe91e06..acd242de2f050ba3f05529bc7ce3b2fbd1892eb5 100644 (file)
@@ -1,5 +1,22 @@
 2006-05-18  Raja R Harinath  <rharinath@novell.com>
 
+       Fix #77601
+       * statement.cs (Goto.Resolve): Move responsibility for resolving
+       'goto' to FlowBranching.AddGotoOrigin.
+       (Goto.SetResolvedTarget): New.  Callback to set the
+       LabeledStatement that's the target of the goto.
+       (Goto.DoEmit): Use Leave instead of Br when crossing an
+       unwind-protect boundary.
+       * flowanalysis.cs (FlowBranching.AddGotoOrigin): Rename from
+       LookupLabel and adjust to new semantics.
+       (FlowBranchingToplevel.AddGotoOrigin): Likewise.
+       (FlowBranchingBlock.AddGotoOrigin): Likewise. Use
+       Goto.SetResolvedTarget to update target.
+       (FlowBranchingLabeled.AddGotoOrigin): Likewise.
+       (FlowBranchingException.AddGotoOrigin): Rewrite to be similar to
+       AddBreakOrigin & co.  Delay propagation until ...
+       (FlowBranchingException.Merge): ... this.
+
        * statement.cs (Block.Resolve): Always depend on flow-branching to
        determine unreachability.  Kill workaround that originally emitted
        only one statement after an "unreachable" label (see infloop in
index 1984bc20699408ddf3830d4100619975ee998c36..12feb35f3737869ee08cc57fdb8a5406ea276666 100644 (file)
@@ -618,11 +618,6 @@ namespace Mono.CSharp
 
                protected abstract void AddSibling (UsageVector uv);
 
-               public virtual LabeledStatement LookupLabel (string name, Location loc)
-               {
-                       return Parent.LookupLabel (name, loc);
-               }
-
                protected abstract UsageVector Merge ();
 
                // <summary>
@@ -661,6 +656,12 @@ namespace Mono.CSharp
                        return Parent.AddReturnOrigin (vector, loc);
                }
 
+               // returns true if we crossed an unwind-protected region (try/catch/finally, lock, using, ...)
+               public virtual bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
+               {
+                       return Parent.AddGotoOrigin (vector, goto_stmt);
+               }
+
                public virtual void StealFinallyClauses (ref ArrayList list)
                {
                        Parent.StealFinallyClauses (ref list);
@@ -733,14 +734,16 @@ namespace Mono.CSharp
                        sibling_list = sibling;
                }
 
-               public override LabeledStatement LookupLabel (string name, Location loc)
+               public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
                {
-                       LabeledStatement stmt = Block == null ? null : Block.LookupLabel (name);
+                       LabeledStatement stmt = Block == null ? null : Block.LookupLabel (goto_stmt.Target);
                        if (stmt == null)
-                               return Parent.LookupLabel (name, loc);
+                               return Parent.AddGotoOrigin (vector, goto_stmt);
 
-                       stmt.AddReference ();
-                       return stmt;
+                       // forward jump
+                       goto_stmt.SetResolvedTarget (stmt);
+                       stmt.AddUsageVector (vector);
+                       return false;
                }
 
                protected override UsageVector Merge ()
@@ -802,7 +805,6 @@ namespace Mono.CSharp
 
        public class FlowBranchingLabeled : FlowBranchingBlock
        {
-               bool unreachable, backward_jump;
                LabeledStatement stmt;
                UsageVector actual;
 
@@ -812,34 +814,30 @@ namespace Mono.CSharp
                        this.stmt = stmt;
                        CurrentUsageVector.MergeOrigins (stmt.JumpOrigins);
                        actual = CurrentUsageVector.Clone ();
-                       unreachable = actual.Reachability.IsUnreachable;
 
                        // stand-in for backward jumps
                        CurrentUsageVector.Reachability.Meet (Reachability.Always ());
                }
 
-               public override LabeledStatement LookupLabel (string name, Location loc)
+               public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
                {
-                       if (name != stmt.Name)
-                               return Parent.LookupLabel (name, loc);
+                       if (goto_stmt.Target != stmt.Name)
+                               return Parent.AddGotoOrigin (vector, goto_stmt);
 
-                       unreachable = false;
-                       backward_jump = true;
+                       // backward jump
+                       goto_stmt.SetResolvedTarget (stmt);
+                       actual.MergeOrigins (vector.Clone ());
 
-                       stmt.AddReference ();
-                       return stmt;
+                       return false;
                }
 
                protected override UsageVector Merge ()
                {
                        UsageVector vector = base.Merge ();
 
-                       if (unreachable)
+                       if (actual.Reachability.IsUnreachable)
                                Report.Warning (162, 2, stmt.loc, "Unreachable code detected");
 
-                       if (backward_jump)
-                               return vector;
-
                        actual.MergeChild (vector, false);
                        return actual;
                }
@@ -899,22 +897,23 @@ namespace Mono.CSharp
                        // nothing to do
                }
 
-               public override LabeledStatement LookupLabel (string name, Location loc)
+               public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
                {
+                       string name = goto_stmt.Target;
                        LabeledStatement s = Block.LookupLabel (name);
                        if (s != null)
                                throw new InternalErrorException ("Shouldn't get here");
 
-                       if (Parent != null) {
-                               s = Parent.LookupLabel (name, loc);
-                               if (s != null) {
-                                       Report.Error (1632, loc, "Control cannot leave the body of an anonymous method");
-                                       return null;
-                               }
+                       if (Parent == null) {
+                               Report.Error (159, goto_stmt.loc, "No such label `{0}' in this scope", name);
+                               return false;
                        }
 
-                       Report.Error (159, loc, "No such label `{0}' in this scope", name);
-                       return null;
+                       int errors = Report.Errors;
+                       Parent.AddGotoOrigin (vector, goto_stmt);
+                       if (errors == Report.Errors)
+                               Report.Error (1632, goto_stmt.loc, "Control cannot leave the body of an anonymous method");
+                       return false;
                }
 
                public Reachability End ()
@@ -940,6 +939,20 @@ namespace Mono.CSharp
                UsageVector break_origins;
                UsageVector continue_origins;
                UsageVector return_origins;
+               GotoOrigin goto_origins;
+
+               class GotoOrigin {
+                       public GotoOrigin Next;
+                       public Goto GotoStmt;
+                       public UsageVector Vector;
+
+                       public GotoOrigin (UsageVector vector, Goto goto_stmt, GotoOrigin next)
+                       {
+                               Vector = vector;
+                               GotoStmt = goto_stmt;
+                               Next = next;
+                       }
+               }
 
                bool emit_finally;
 
@@ -1023,6 +1036,19 @@ namespace Mono.CSharp
                        return true;
                }
 
+               public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
+               {
+                       LabeledStatement s = current_vector.Block == null ? null : current_vector.Block.LookupLabel (goto_stmt.Target);
+                       if (s != null)
+                               throw new InternalErrorException ("Shouldn't get here");
+
+                       if (finally_vector != null)
+                               Report.Error (157, goto_stmt.loc, "Control cannot leave the body of a finally clause");
+                       else
+                               goto_origins = new GotoOrigin (vector.Clone (), goto_stmt, goto_origins);
+                       return true;
+               }
+
                public override void StealFinallyClauses (ref ArrayList list)
                {
                        if (list == null)
@@ -1036,23 +1062,6 @@ namespace Mono.CSharp
                        get { return emit_finally; }
                }
 
-               public override LabeledStatement LookupLabel (string name, Location loc)
-               {
-                       if (current_vector.Block == null)
-                               return base.LookupLabel (name, loc);
-
-                       LabeledStatement s = current_vector.Block.LookupLabel (name);
-                       if (s != null)
-                               return s;
-
-                       if (finally_vector != null) {
-                               Report.Error (157, loc, "Control cannot leave the body of a finally clause");
-                               return null;
-                       }
-
-                       return base.LookupLabel (name, loc);
-               }
-
                protected override UsageVector Merge ()
                {
                        Report.Debug (2, "  MERGING TRY/CATCH", Name);
@@ -1083,6 +1092,13 @@ namespace Mono.CSharp
                                        Parent.AddReturnOrigin (origin, origin.Location);
                        }
 
+                       for (GotoOrigin origin = goto_origins; origin != null; origin = origin.Next) {
+                               if (finally_vector != null)
+                                       origin.Vector.MergeChild (finally_vector, false);
+                               if (!origin.Vector.Reachability.IsUnreachable)
+                                       Parent.AddGotoOrigin (origin.Vector, origin.GotoStmt);
+                       }
+
                        return vector;
                }
        }
index 5fb7fc5b1582f2e2a621215bbc45c7fb08e1cca8..859cdba97be8bd4e2546fde84ee13f93e86a0ebb 100644 (file)
@@ -582,7 +582,7 @@ namespace Mono.CSharp {
                        loc = l;
                }
 
-               bool in_exc;
+               bool unwind_protect;
 
                public override bool Resolve (EmitContext ec)
                {
@@ -624,8 +624,8 @@ namespace Mono.CSharp {
                        }
 
                        int errors = Report.Errors;
-                       in_exc = ec.CurrentBranching.AddReturnOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
-                       if (in_exc)
+                       unwind_protect = ec.CurrentBranching.AddReturnOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
+                       if (unwind_protect)
                                ec.NeedReturnLabel ();
                        ec.CurrentBranching.CurrentUsageVector.Return ();
                        return errors == Report.Errors;
@@ -636,11 +636,11 @@ namespace Mono.CSharp {
                        if (Expr != null) {
                                Expr.Emit (ec);
 
-                               if (in_exc)
+                               if (unwind_protect)
                                        ec.ig.Emit (OpCodes.Stloc, ec.TemporaryReturn ());
                        }
 
-                       if (in_exc)
+                       if (unwind_protect)
                                ec.ig.Emit (OpCodes.Leave, ec.ReturnLabel);
                        else
                                ec.ig.Emit (OpCodes.Ret);
@@ -650,20 +650,14 @@ namespace Mono.CSharp {
        public class Goto : Statement {
                string target;
                LabeledStatement label;
+               bool unwind_protect;
                
                public override bool Resolve (EmitContext ec)
                {
-                       label = ec.CurrentBranching.LookupLabel (target, loc);
-                       if (label == null)
-                               return false;
-
-                       // If this is a forward goto.
-                       if (!label.IsDefined)
-                               label.AddUsageVector (ec.CurrentBranching.CurrentUsageVector);
-
+                       int errors = Report.Errors;
+                       unwind_protect = ec.CurrentBranching.AddGotoOrigin (ec.CurrentBranching.CurrentUsageVector, this);
                        ec.CurrentBranching.CurrentUsageVector.Goto ();
-
-                       return true;
+                       return errors == Report.Errors;
                }
                
                public Goto (string label, Location l)
@@ -676,10 +670,18 @@ namespace Mono.CSharp {
                        get { return target; }
                }
 
+               public void SetResolvedTarget (LabeledStatement label)
+               {
+                       this.label = label;
+                       label.AddReference ();
+               }
+
                protected override void DoEmit (EmitContext ec)
                {
+                       if (label == null)
+                               throw new InternalErrorException ("goto emitted before target resolved");
                        Label l = label.LabelTarget (ec);
-                       ec.ig.Emit (OpCodes.Br, l);
+                       ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, l);
                }
        }
 
@@ -910,19 +912,19 @@ namespace Mono.CSharp {
                        loc = l;
                }
 
-               bool crossing_exc;
+               bool unwind_protect;
 
                public override bool Resolve (EmitContext ec)
                {
                        int errors = Report.Errors;
-                       crossing_exc = ec.CurrentBranching.AddBreakOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
+                       unwind_protect = ec.CurrentBranching.AddBreakOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
                        ec.CurrentBranching.CurrentUsageVector.Goto ();
                        return errors == Report.Errors;
                }
 
                protected override void DoEmit (EmitContext ec)
                {
-                       ec.ig.Emit (crossing_exc ? OpCodes.Leave : OpCodes.Br, ec.LoopEnd);
+                       ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopEnd);
                }
        }
 
@@ -933,19 +935,19 @@ namespace Mono.CSharp {
                        loc = l;
                }
 
-               bool crossing_exc;
+               bool unwind_protect;
 
                public override bool Resolve (EmitContext ec)
                {
                        int errors = Report.Errors;
-                       crossing_exc = ec.CurrentBranching.AddContinueOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
+                       unwind_protect = ec.CurrentBranching.AddContinueOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
                        ec.CurrentBranching.CurrentUsageVector.Goto ();
                        return errors == Report.Errors;
                }
 
                protected override void DoEmit (EmitContext ec)
                {
-                       ec.ig.Emit (crossing_exc ? OpCodes.Leave : OpCodes.Br, ec.LoopBegin);
+                       ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopBegin);
                }
        }
 
index 7d479e0c1858f69246fd79a95ce2d5b6048f38e8..361238aeee42345e1043f3a49504b61c934a6fa3 100644 (file)
@@ -1,5 +1,7 @@
 2006-05-18  Raja R Harinath  <rharinath@novell.com>
 
+       * test-518.cs: New test based on #77601.
+
        * test-514.cs: New test from #76148.
        * test-515.cs, test-516.cs: New tests based on #77755.
        * test-517.cs: New test based on #75255.
diff --git a/mcs/tests/test-518.cs b/mcs/tests/test-518.cs
new file mode 100644 (file)
index 0000000..d4e4841
--- /dev/null
@@ -0,0 +1,14 @@
+class Foo {
+       static int Main ()
+       {
+               int ret = 1;
+               try {
+                       goto done;
+               } finally {
+                       ret = 0;
+               }
+       done:
+               return ret;
+       }
+}
+