X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fgmcs%2Fflowanalysis.cs;h=fac60a500f305dc6a386406e02ebcbf30dfa7229;hb=bd316288ae3fa0cb6f03b367716d04d5244c5d04;hp=18f5714392490aea3015ffdd0fffa4ec53737b3c;hpb=699e59742843044f6efa1726b7cb64f19d909e64;p=mono.git diff --git a/mcs/gmcs/flowanalysis.cs b/mcs/gmcs/flowanalysis.cs index 18f57143924..fac60a500f3 100644 --- a/mcs/gmcs/flowanalysis.cs +++ b/mcs/gmcs/flowanalysis.cs @@ -168,10 +168,15 @@ namespace Mono.CSharp return; } + a.And (b, do_break); + } + + public void And (Reachability b, bool do_break) + { // // `break' does not "break" in a Switch or a LoopBlock // - bool a_breaks = do_break && a.AlwaysBreaks; + bool a_breaks = do_break && AlwaysBreaks; bool b_breaks = do_break && b.AlwaysBreaks; bool a_has_barrier, b_has_barrier; @@ -180,55 +185,55 @@ namespace Mono.CSharp // This is the normal case: the code following a barrier // cannot be reached. // - a_has_barrier = a.AlwaysHasBarrier; + a_has_barrier = AlwaysHasBarrier; b_has_barrier = b.AlwaysHasBarrier; } else { // // Special case for Switch and LoopBlocks: we can reach the // code after the barrier via the `break'. // - a_has_barrier = !a.AlwaysBreaks && a.AlwaysHasBarrier; + a_has_barrier = !AlwaysBreaks && AlwaysHasBarrier; b_has_barrier = !b.AlwaysBreaks && b.AlwaysHasBarrier; } - bool a_unreachable = a_breaks || a.AlwaysThrows || a_has_barrier; + bool a_unreachable = a_breaks || AlwaysThrows || a_has_barrier; bool b_unreachable = b_breaks || b.AlwaysThrows || b_has_barrier; // // Do all code paths always return ? // - if (a.AlwaysReturns) { + if (AlwaysReturns) { if (b.AlwaysReturns || b_unreachable) - a.returns = FlowReturns.Always; + returns = FlowReturns.Always; else - a.returns = FlowReturns.Sometimes; + returns = FlowReturns.Sometimes; } else if (b.AlwaysReturns) { - if (a.AlwaysReturns || a_unreachable) - a.returns = FlowReturns.Always; + if (AlwaysReturns || a_unreachable) + returns = FlowReturns.Always; else - a.returns = FlowReturns.Sometimes; - } else if (!a.MayReturn) { + returns = FlowReturns.Sometimes; + } else if (!MayReturn) { if (b.MayReturn) - a.returns = FlowReturns.Sometimes; + returns = FlowReturns.Sometimes; else - a.returns = FlowReturns.Never; + returns = FlowReturns.Never; } else if (!b.MayReturn) { - if (a.MayReturn) - a.returns = FlowReturns.Sometimes; + if (MayReturn) + returns = FlowReturns.Sometimes; else - a.returns = FlowReturns.Never; + returns = FlowReturns.Never; } - a.breaks = AndFlowReturns (a.breaks, b.breaks); - a.throws = AndFlowReturns (a.throws, b.throws); - a.barrier = AndFlowReturns (a.barrier, b.barrier); + breaks = AndFlowReturns (breaks, b.breaks); + throws = AndFlowReturns (throws, b.throws); + barrier = AndFlowReturns (barrier, b.barrier); if (a_unreachable && b_unreachable) - a.barrier = FlowReturns.Always; + barrier = FlowReturns.Always; else if (a_unreachable || b_unreachable) - a.barrier = FlowReturns.Sometimes; + barrier = FlowReturns.Sometimes; else - a.barrier = FlowReturns.Never; + barrier = FlowReturns.Never; } public void Or (Reachability b) @@ -367,7 +372,7 @@ namespace Mono.CSharp throw new InvalidOperationException (); case BranchingType.Switch: - return new FlowBranchingBlock (parent, type, SiblingType.SwitchSection, block, loc); + return new FlowBranchingSwitch (parent, block, loc); case BranchingType.SwitchSection: return new FlowBranchingBlock (parent, type, SiblingType.Block, block, loc); @@ -647,19 +652,13 @@ namespace Mono.CSharp // then we do always return (or stay in the // loop forever). new_r.SetReturns (); - } + } new_r.SetBarrier (); - } else { - if (new_r.Returns == FlowReturns.Always) { - // We're either finite or we may leave the loop. - new_r.SetReturnsSometimes (); - } - if (new_r.Throws == FlowReturns.Always) { - // We're either finite or we may leave the loop. - new_r.SetThrowsSometimes (); - } - } + } + + if (may_leave_loop) + new_r.ResetBarrier (); } else if (branching.Type == BranchingType.Switch) { if (new_r.MayBreak || new_r.MayReturn) new_r.ResetBarrier (); @@ -689,7 +688,10 @@ namespace Mono.CSharp if (result.ParameterVector != null) parameters.Or (result.ParameterVector); - reachability.Or (new_r); + if ((branching.Type == BranchingType.Block) && branching.Block.Implicit) + reachability = new_r.Clone (); + else + reachability.Or (new_r); Report.Debug (2, " MERGING CHILD DONE", this, result, new_r, reachability); @@ -758,23 +760,26 @@ namespace Mono.CSharp for (UsageVector vector = o_vectors; vector != null; vector = vector.Next) { - Report.Debug (1, " MERGING JUMP ORIGIN", vector); + Report.Debug (1, " MERGING JUMP ORIGIN", vector, + first, locals, vector.Locals); if (first) { if (locals != null && vector.Locals != null) - locals.Or (vector.locals); + locals.Or (vector.locals); if (parameters != null) parameters.Or (vector.parameters); first = false; } else { - if (locals != null && vector.Locals != null) - locals.And (vector.locals); - if (parameters != null) - parameters.And (vector.parameters); - } + if (locals != null) + locals.And (vector.locals); + if (parameters != null) + parameters.And (vector.parameters); + } Reachability.And (ref reachability, vector.Reachability, true); + + Report.Debug (1, " MERGING JUMP ORIGIN #1", vector); } Report.Debug (1, " MERGING JUMP ORIGINS DONE", this); @@ -802,18 +807,18 @@ namespace Mono.CSharp Report.Debug (1, " MERGING FINALLY ORIGIN DONE", this); } - public void MergeBreakOrigins (UsageVector o_vectors) + public void MergeBreakOrigins (FlowBranching branching, UsageVector o_vectors) { Report.Debug (1, " MERGING BREAK ORIGINS", this); if (o_vectors == null) return; - bool first = true; + bool first = branching.Infinite; for (UsageVector vector = o_vectors; vector != null; vector = vector.Next) { - Report.Debug (1, " MERGING BREAK ORIGIN", vector); + Report.Debug (1, " MERGING BREAK ORIGIN", vector, first); if (first) { if (locals != null && vector.Locals != null) @@ -828,6 +833,8 @@ namespace Mono.CSharp if (parameters != null) parameters.And (vector.parameters); } + + reachability.And (vector.Reachability, false); } Report.Debug (1, " MERGING BREAK ORIGINS DONE", this); @@ -1019,9 +1026,8 @@ namespace Mono.CSharp if (var.IsAssigned (parameters)) continue; - Report.Error (177, loc, "The out parameter `" + - var.Name + "' must be " + - "assigned before control leaves the current method."); + Report.Error (177, loc, "The out parameter `{0}' must be assigned to before control leaves the current method", + var.Name); } } @@ -1135,7 +1141,7 @@ namespace Mono.CSharp throw new NotSupportedException (); UsageVector vector = new UsageVector ( - SiblingType.Conditional, null, Block, Location, + SiblingType.Block, null, Block, Location, param_map.Length, local_map.Length); UsageVector result = vector.MergeChild (this); @@ -1165,29 +1171,11 @@ namespace Mono.CSharp return false; } - // - // Checks whether we're in a `catch' block. - // - public virtual bool InCatch () + public virtual bool InTryWithCatch () { if (Parent != null) - return Parent.InCatch (); - else - return false; - } - - // - // Checks whether we're in a `finally' block. - // - public virtual bool InFinally (bool is_return) - { - if (!is_return && - ((Type == BranchingType.Loop) || (Type == BranchingType.Switch))) - return false; - else if (Parent != null) - return Parent.InFinally (is_return); - else - return false; + return Parent.InTryWithCatch (); + return false; } public virtual bool InLoop () @@ -1363,7 +1351,32 @@ namespace Mono.CSharp { UsageVector vector = base.Merge (); - vector.MergeBreakOrigins (break_origins); + vector.MergeBreakOrigins (this, break_origins); + + return vector; + } + } + + public class FlowBranchingSwitch : FlowBranchingBlock + { + UsageVector break_origins; + + public FlowBranchingSwitch (FlowBranching parent, Block block, Location loc) + : base (parent, BranchingType.Switch, SiblingType.SwitchSection, block, loc) + { } + + public override void AddBreakVector (UsageVector vector) + { + vector = vector.Clone (); + vector.Next = break_origins; + break_origins = vector; + } + + protected override UsageVector Merge () + { + UsageVector vector = base.Merge (); + + vector.MergeBreakOrigins (this, break_origins); return vector; } @@ -1377,7 +1390,6 @@ namespace Mono.CSharp UsageVector finally_vector; UsageVector finally_origins; bool emit_finally; - bool in_try; public FlowBranchingException (FlowBranching parent, ExceptionStatement stmt) @@ -1393,15 +1405,12 @@ namespace Mono.CSharp if (sibling.Type == SiblingType.Try) { sibling.Next = catch_vectors; catch_vectors = sibling; - in_try = true; } else if (sibling.Type == SiblingType.Catch) { sibling.Next = catch_vectors; catch_vectors = sibling; - in_try = false; } else if (sibling.Type == SiblingType.Finally) { sibling.MergeFinallyOrigins (finally_origins); finally_vector = sibling; - in_try = false; } else throw new InvalidOperationException (); @@ -1417,14 +1426,18 @@ namespace Mono.CSharp return finally_vector == null; } - public override bool InCatch () + public override bool InTryWithCatch () { - return !in_try && (finally_vector == null); - } + if (finally_vector == null) { + Try t = stmt as Try; + if (t != null && t.HasCatch) + return true; + } - public override bool InFinally (bool is_return) - { - return finally_vector != null; + if (Parent != null) + return Parent.InTryWithCatch (); + + return false; } public override bool BreakCrossesTryCatchBoundary () @@ -1462,9 +1475,8 @@ namespace Mono.CSharp return s; if (finally_vector != null) { - Report.Error ( - 157, loc, "Control can not leave the body " + - "of the finally block"); + Report.Error (157, loc, + "Control cannot leave the body of a finally clause"); return null; } @@ -1631,9 +1643,8 @@ namespace Mono.CSharp if (!branching.IsFieldAssigned (vi, field.Name)) { Report.Error (171, loc, - "Field `" + TypeManager.CSharpName (Type) + - "." + field.Name + "' must be fully initialized " + - "before control leaves the constructor"); + "Field `{0}' must be fully assigned before control leaves the constructor", + TypeManager.GetFullNameSignature (field)); ok = false; } } @@ -1675,13 +1686,15 @@ namespace Mono.CSharp if (type is TypeBuilder) { TypeContainer tc = TypeManager.LookupTypeContainer (type); - ArrayList fields = tc.Fields; + ArrayList fields = null; + if (tc != null) + fields = tc.Fields; ArrayList public_fields = new ArrayList (); ArrayList non_public_fields = new ArrayList (); if (fields != null) { - foreach (Field field in fields) { + foreach (FieldMember field in fields) { if ((field.ModFlags & Modifiers.STATIC) != 0) continue; if ((field.ModFlags & Modifiers.PUBLIC) != 0) @@ -1734,7 +1747,7 @@ namespace Mono.CSharp field_hash.Add (field.Name, ++Length); else if (sinfo [i].InTransit) { Report.Error (523, String.Format ( - "Struct member '{0}.{1}' of type '{2}' causes " + + "Struct member `{0}.{1}' of type `{2}' causes " + "a cycle in the structure layout", type, field.Name, sinfo [i].Type)); sinfo [i] = null; @@ -1886,7 +1899,9 @@ namespace Mono.CSharp public bool IsAssigned (EmitContext ec) { - return !ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (this); + return !ec.DoFlowAnalysis || + ec.OmitStructFlowAnalysis && TypeInfo.IsStruct || + ec.CurrentBranching.IsAssigned (this); } public bool IsAssigned (EmitContext ec, Location loc) @@ -1946,7 +1961,9 @@ namespace Mono.CSharp public bool IsFieldAssigned (EmitContext ec, string name, Location loc) { - if (!ec.DoFlowAnalysis || ec.CurrentBranching.IsFieldAssigned (this, name)) + if (!ec.DoFlowAnalysis || + ec.OmitStructFlowAnalysis && TypeInfo.IsStruct || + ec.CurrentBranching.IsFieldAssigned (this, name)) return true; Report.Error (170, loc, @@ -2210,7 +2227,12 @@ namespace Mono.CSharp // public void And (MyBitVector new_vector) { - BitArray new_array = new_vector.Vector; + BitArray new_array; + + if (new_vector != null) + new_array = new_vector.Vector; + else + new_array = new BitArray (Count, false); initialize_vector ();