X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fstatement.cs;h=2bc9aed2c37c9a398c11dbbe5cdd7b4f4e14b4c2;hb=5ad1099341581dee94f77b32db728918e90fa64f;hp=b3043994dc578939a06dfabb58f5663e03496865;hpb=d12330eda7746321b4611865d11e932e53ac55b8;p=mono.git diff --git a/mcs/mcs/statement.cs b/mcs/mcs/statement.cs index b3043994dc5..2bc9aed2c37 100644 --- a/mcs/mcs/statement.cs +++ b/mcs/mcs/statement.cs @@ -89,13 +89,15 @@ namespace Mono.CSharp { { if (reachable) { fc.UnreachableReported = false; - return DoFlowAnalysis (fc); + var res = DoFlowAnalysis (fc); + fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = null; + return res; } // // Special handling cases // - if (this is Block || this is SwitchLabel) { + if (this is Block) { return DoFlowAnalysis (fc); } @@ -264,30 +266,42 @@ namespace Mono.CSharp { protected override bool DoFlowAnalysis (FlowAnalysisContext fc) { + fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment; + expr.FlowAnalysis (fc); - var da = fc.BranchDefiniteAssignment (); + var da_false = new DefiniteAssignmentBitSet (fc.DefiniteAssignmentOnFalse); + + fc.DefiniteAssignment = fc.DefiniteAssignmentOnTrue; + fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = null; var res = TrueStatement.FlowAnalysis (fc); if (FalseStatement == null) { - fc.DefiniteAssignment = da; + if (true_returns) + fc.DefiniteAssignment = da_false; + else + fc.DefiniteAssignment &= da_false; + return false; } - var da_true = fc.DefiniteAssignment; if (true_returns) { - fc.DefiniteAssignment = da; + fc.DefiniteAssignment = da_false; return FalseStatement.FlowAnalysis (fc); } - fc.DefiniteAssignment = new DefiniteAssignmentBitSet (da); + var da_true = fc.DefiniteAssignment; + + fc.DefiniteAssignment = da_false; res &= FalseStatement.FlowAnalysis (fc); - if (false_returns) - fc.DefiniteAssignment = da_true; - else - fc.DefiniteAssignment &= da_true; + if (!TrueStatement.IsUnreachable) { + if (false_returns || FalseStatement.IsUnreachable) + fc.DefiniteAssignment = da_true; + else + fc.DefiniteAssignment &= da_true; + } return res; } @@ -403,13 +417,12 @@ namespace Mono.CSharp { protected override bool DoFlowAnalysis (FlowAnalysisContext fc) { - var dat = fc.BranchDefiniteAssignment (); - var res = Statement.FlowAnalysis (fc); + fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment; expr.FlowAnalysis (fc); - fc.DefiniteAssignment = dat | fc.DefiniteAssignment; + fc.DefiniteAssignment = fc.DefiniteAssignmentOnFalse; if (res && !iterator_reachable) return !end_reachable; @@ -552,11 +565,13 @@ namespace Mono.CSharp { protected override bool DoFlowAnalysis (FlowAnalysisContext fc) { + fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment; + expr.FlowAnalysis (fc); - DefiniteAssignmentBitSet das; - - das = fc.BranchDefiniteAssignment (); + fc.DefiniteAssignment = fc.DefiniteAssignmentOnTrue; + var da_false = new DefiniteAssignmentBitSet (fc.DefiniteAssignmentOnFalse); + fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = null; Statement.FlowAnalysis (fc); @@ -564,11 +579,11 @@ namespace Mono.CSharp { // Special case infinite while with breaks // if (end_reachable_das != null) { - das = DefiniteAssignmentBitSet.And (end_reachable_das); + da_false = DefiniteAssignmentBitSet.And (end_reachable_das); end_reachable_das = null; } - fc.DefiniteAssignment = das; + fc.DefiniteAssignment = da_false; if (infinite && !end_reachable) return true; @@ -635,7 +650,7 @@ namespace Mono.CSharp { public class For : LoopStatement { bool infinite, empty, iterator_reachable, end_reachable; - List end_reachability; + List end_reachable_das; public For (Location l) : base (null) @@ -684,18 +699,36 @@ namespace Mono.CSharp { { Initializer.FlowAnalysis (fc); - if (Condition != null) - Condition.FlowAnalysis (fc); + DefiniteAssignmentBitSet da_false; + if (Condition != null) { + fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment; - var das = fc.BranchDefiniteAssignment (); + Condition.FlowAnalysis (fc); + fc.DefiniteAssignment = fc.DefiniteAssignmentOnTrue; + da_false = new DefiniteAssignmentBitSet (fc.DefiniteAssignmentOnFalse); + fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = null; + } else { + da_false = fc.BranchDefiniteAssignment (); + } Statement.FlowAnalysis (fc); Iterator.FlowAnalysis (fc); - fc.DefiniteAssignment = das; + // + // Special case infinite for with breaks + // + if (end_reachable_das != null) { + da_false = DefiniteAssignmentBitSet.And (end_reachable_das); + end_reachable_das = null; + } + + fc.DefiniteAssignment = da_false; + + if (infinite && !end_reachable) + return true; - return infinite && !end_reachable; + return false; } public override Reachability MarkReachable (Reachability rc) @@ -795,10 +828,10 @@ namespace Mono.CSharp { if (!infinite) return; - if (end_reachability == null) - end_reachability = new List (); + if (end_reachable_das == null) + end_reachable_das = new List (); - end_reachability.Add (fc.DefiniteAssignment); + end_reachable_das.Add (fc.DefiniteAssignment); } public override void SetEndReachable () @@ -1067,9 +1100,9 @@ namespace Mono.CSharp { return true; if (fc.TryFinally != null) { - fc.TryFinally.RegisterOutParametersCheck (new DefiniteAssignmentBitSet (fc.DefiniteAssignment)); + fc.TryFinally.RegisterForControlExitCheck (new DefiniteAssignmentBitSet (fc.DefiniteAssignment)); } else { - fc.ParametersBlock.CheckOutParametersAssignment (fc); + fc.ParametersBlock.CheckControlExit (fc); } return true; @@ -1129,14 +1162,17 @@ namespace Mono.CSharp { expr = EmptyExpression.Null; return true; } + + if (storey.ReturnType.IsGenericTask) + block_return_type = storey.ReturnType.TypeArguments[0]; } if (ec.CurrentIterator != null) { Error_ReturnFromIterator (ec); - } else if (ec.ReturnType != InternalType.ErrorType) { + } else if (block_return_type != InternalType.ErrorType) { ec.Report.Error (126, loc, "An object of a type convertible to `{0}' is required for the return statement", - ec.ReturnType.GetSignatureForError ()); + block_return_type.GetSignatureForError ()); } return false; @@ -1461,7 +1497,9 @@ namespace Mono.CSharp { protected override void CloneTo (CloneContext clonectx, Statement target) { - // nothing to clone + var t = (LabeledStatement) target; + + t.block = clonectx.RemapBlockCopy (block); } public override bool Resolve (BlockContext bc) @@ -1503,6 +1541,7 @@ namespace Mono.CSharp { return; referenced = true; + MarkReachable (rc); // // Label is final target when goto jumps out of try block with @@ -1511,7 +1550,6 @@ namespace Mono.CSharp { // explicit label not just marker // if (finalTarget) { - MarkReachable (rc); this.finalTarget = true; return; } @@ -1553,7 +1591,20 @@ namespace Mono.CSharp { { ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.Switch.DefaultLabel.GetILLabel (ec)); } - + + public override Reachability MarkReachable (Reachability rc) + { + if (!rc.IsUnreachable) { + var label = switch_statement.DefaultLabel; + if (label.IsUnreachable) { + label.MarkReachable (rc); + switch_statement.Block.ScanGotoJump (label); + } + } + + return base.MarkReachable (rc); + } + public override object Accept (StructuralVisitor visitor) { return visitor.Visit (this); @@ -1613,6 +1664,7 @@ namespace Mono.CSharp { ec.Switch.RegisterGotoCase (this, res); base.Resolve (ec); + expr = res; return true; } @@ -1628,6 +1680,19 @@ namespace Mono.CSharp { target.expr = expr.Clone (clonectx); } + + public override Reachability MarkReachable (Reachability rc) + { + if (!rc.IsUnreachable) { + var label = switch_statement.FindLabel ((Constant) expr); + if (label.IsUnreachable) { + label.MarkReachable (rc); + switch_statement.Block.ScanGotoJump (label); + } + } + + return base.MarkReachable (rc); + } public override object Accept (StructuralVisitor visitor) { @@ -1638,6 +1703,7 @@ namespace Mono.CSharp { public abstract class SwitchGoto : Statement { protected bool unwind_protect; + protected Switch switch_statement; protected SwitchGoto (Location loc) { @@ -1654,6 +1720,7 @@ namespace Mono.CSharp { CheckExitBoundaries (bc, bc.Switch.Block); unwind_protect = bc.HasAny (ResolveContext.Options.TryScope | ResolveContext.Options.CatchScope); + switch_statement = bc.Switch; return true; } @@ -2740,17 +2807,9 @@ namespace Mono.CSharp { statements.Add (s); } - public int AssignableSlots { - get { - // FIXME: HACK, we don't know the block available variables count now, so set this high enough - return 4096; -// return assignable_slots; - } - } - public LabeledStatement LookupLabel (string name) { - return ParametersBlock.TopBlock.GetLabel (name, this); + return ParametersBlock.GetLabel (name, this); } public override Reachability MarkReachable (Reachability rc) @@ -2858,13 +2917,6 @@ namespace Mono.CSharp { end_unreachable = s.FlowAnalysis (fc); if (s.IsUnreachable) { - // - // This is kind of a hack, switch label is unreachable because we need to mark - // switch section end but at the same time we need to run Emit on it - // - if (s is SwitchLabel) - continue; - statements[startIndex] = new EmptyStatement (s.loc); continue; } @@ -2882,7 +2934,7 @@ namespace Mono.CSharp { // X label is reachable only via goto not as another statement after if. We need // this for flow-analysis only to carry variable info correctly. // - if (end_unreachable) { // s is ExitStatement) { + if (end_unreachable) { for (++startIndex; startIndex < statements.Count; ++startIndex) { s = statements[startIndex]; if (s is SwitchLabel) { @@ -2916,7 +2968,7 @@ namespace Mono.CSharp { } var rc = new Reachability (); - for (; i < statements.Count; ++i) { + for (++i; i < statements.Count; ++i) { var s = statements[i]; rc = s.MarkReachable (rc); if (rc.IsUnreachable) @@ -2940,7 +2992,7 @@ namespace Mono.CSharp { #if DEBUG public override string ToString () { - return String.Format ("{0} ({1}:{2})", GetType (), ID, StartLocation); + return String.Format ("{0}: ID={1} Clone={2} Location={3}", GetType (), ID, clone_id != 0, StartLocation); } #endif @@ -2948,7 +3000,7 @@ namespace Mono.CSharp { { Block target = (Block) t; #if DEBUG - target.clone_id = clone_id_counter++; + target.clone_id = ++clone_id_counter; #endif clonectx.AddBlockMap (this, target); @@ -3428,6 +3480,7 @@ namespace Mono.CSharp { protected bool resolved; protected ToplevelBlock top_block; protected StateMachine state_machine; + protected Dictionary labels; public ParametersBlock (Block parent, ParametersCompiled parameters, Location start, Flags flags = 0) : base (parent, 0, start, start) @@ -3533,12 +3586,12 @@ namespace Mono.CSharp { // // Checks whether all `out' parameters have been assigned. // - public void CheckOutParametersAssignment (FlowAnalysisContext fc) + public void CheckControlExit (FlowAnalysisContext fc) { - CheckOutParametersAssignment (fc, fc.DefiniteAssignment); + CheckControlExit (fc, fc.DefiniteAssignment); } - public void CheckOutParametersAssignment (FlowAnalysisContext fc, DefiniteAssignmentBitSet dat) + public virtual void CheckControlExit (FlowAnalysisContext fc, DefiniteAssignmentBitSet dat) { if (parameter_info == null) return; @@ -3556,6 +3609,46 @@ namespace Mono.CSharp { } } + protected override void CloneTo (CloneContext clonectx, Statement t) + { + base.CloneTo (clonectx, t); + + var target = (ParametersBlock) t; + + // + // Clone label statements as well as they contain block reference + // + var pb = this; + while (true) { + if (pb.labels != null) { + target.labels = new Dictionary (); + + foreach (var entry in pb.labels) { + var list = entry.Value as List; + + if (list != null) { + var list_clone = new List (); + foreach (var lentry in list) { + list_clone.Add (RemapLabeledStatement (lentry, lentry.Block, clonectx.RemapBlockCopy (lentry.Block))); + } + + target.labels.Add (entry.Key, list_clone); + } else { + var labeled = (LabeledStatement) entry.Value; + target.labels.Add (entry.Key, RemapLabeledStatement (labeled, labeled.Block, clonectx.RemapBlockCopy (labeled.Block))); + } + } + + break; + } + + if (pb.Parent == null) + break; + + pb = pb.Parent.ParametersBlock; + } + } + public override Expression CreateExpressionTree (ResolveContext ec) { if (statements.Count == 1) { @@ -3594,11 +3687,48 @@ namespace Mono.CSharp { var res = base.DoFlowAnalysis (fc); if (HasReachableClosingBrace) - CheckOutParametersAssignment (fc); + CheckControlExit (fc); return res; } + public LabeledStatement GetLabel (string name, Block block) + { + // + // Cloned parameters blocks can have their own cloned version of top-level labels + // + if (labels == null) { + if (Parent != null) + return Parent.ParametersBlock.GetLabel (name, block); + + return null; + } + + object value; + if (!labels.TryGetValue (name, out value)) { + return null; + } + + var label = value as LabeledStatement; + Block b = block; + if (label != null) { + do { + if (label.Block == b) + return label; + b = b.Parent; + } while (b != null); + } else { + List list = (List) value; + for (int i = 0; i < list.Count; ++i) { + label = list[i]; + if (label.Block == b) + return label; + } + } + + return null; + } + public ParameterInfo GetParameterInfo (Parameter p) { for (int i = 0; i < parameters.Count; ++i) { @@ -3638,6 +3768,17 @@ namespace Mono.CSharp { } } + static LabeledStatement RemapLabeledStatement (LabeledStatement stmt, Block src, Block dst) + { + var src_stmts = src.Statements; + for (int i = 0; i < src_stmts.Count; ++i) { + if (src_stmts[i] == stmt) + return (LabeledStatement) dst.Statements[i]; + } + + throw new InternalErrorException ("Should never be reached"); + } + public override bool Resolve (BlockContext bc) { // TODO: if ((flags & Flags.Resolved) != 0) @@ -3657,7 +3798,7 @@ namespace Mono.CSharp { return false; } catch (Exception e) { - if (e is CompletionResult || bc.Report.IsDisabled || e is FatalException || bc.Report.Printer is NullReportPrinter) + if (e is CompletionResult || bc.Report.IsDisabled || e is FatalException || bc.Report.Printer is NullReportPrinter || bc.Module.Compiler.Settings.BreakOnInternalError) throw; if (bc.CurrentBlock != null) { @@ -3665,9 +3806,6 @@ namespace Mono.CSharp { } else { bc.Report.Error (587, "Internal compiler error: {0}", e.Message); } - - if (bc.Module.Compiler.Settings.DebugFlags > 0) - throw; } // @@ -3773,7 +3911,6 @@ namespace Mono.CSharp { LocalVariable this_variable; CompilerContext compiler; Dictionary names; - Dictionary labels; List this_references; @@ -4064,36 +4201,6 @@ namespace Mono.CSharp { return false; } - public LabeledStatement GetLabel (string name, Block block) - { - if (labels == null) - return null; - - object value; - if (!labels.TryGetValue (name, out value)) { - return null; - } - - var label = value as LabeledStatement; - Block b = block; - if (label != null) { - do { - if (label.Block == b.Original) - return label; - b = b.Parent; - } while (b != null); - } else { - List list = (List) value; - for (int i = 0; i < list.Count; ++i) { - label = list[i]; - if (label.Block == b.Original) - return label; - } - } - - return null; - } - // // This is used by non-static `struct' constructors which do not have an // initializer - in this case, the constructor must initialize all of the @@ -4111,21 +4218,16 @@ namespace Mono.CSharp { this_variable.PrepareAssignmentAnalysis (bc); } - public bool IsThisAssigned (FlowAnalysisContext fc) + public override void CheckControlExit (FlowAnalysisContext fc, DefiniteAssignmentBitSet dat) { - return this_variable == null || this_variable.IsThisAssigned (fc, this); - } - - protected override bool DoFlowAnalysis (FlowAnalysisContext fc) - { - var res = base.DoFlowAnalysis (fc); - // // If we're a non-static struct constructor which doesn't have an // initializer, then we must initialize all of the struct's fields. // - IsThisAssigned (fc); - return res; + if (this_variable != null) + this_variable.IsThisAssigned (fc, this); + + base.CheckControlExit (fc, dat); } public override void Emit (EmitContext ec) @@ -4194,7 +4296,7 @@ namespace Mono.CSharp { if ((flags & Flags.NoFlowAnalysis) != 0) return true; - var fc = new FlowAnalysisContext (bc.Module.Compiler, this); + var fc = new FlowAnalysisContext (bc.Module.Compiler, this, bc.AssignmentInfoOffset); try { FlowAnalysis (fc); } catch (Exception e) { @@ -4269,13 +4371,7 @@ namespace Mono.CSharp { if (!SectionStart) return false; - if (IsUnreachable) { - fc.DefiniteAssignment = new DefiniteAssignmentBitSet (fc.SwitchInitialDefinitiveAssignment); - } else { - fc.Report.Error (163, Location, - "Control cannot fall through from one case label `{0}' to another", GetSignatureForError ()); - } - + fc.DefiniteAssignment = new DefiniteAssignmentBitSet (fc.SwitchInitialDefinitiveAssignment); return false; } @@ -4327,7 +4423,7 @@ namespace Mono.CSharp { return visitor.Visit (this); } - string GetSignatureForError () + public string GetSignatureForError () { string label; if (converted == null) @@ -4416,6 +4512,33 @@ namespace Mono.CSharp { } } + class MissingBreak : Statement + { + SwitchLabel label; + + public MissingBreak (SwitchLabel sl) + { + this.label = sl; + this.loc = sl.loc; + } + + protected override void DoEmit (EmitContext ec) + { + } + + protected override void CloneTo (CloneContext clonectx, Statement target) + { + } + + protected override bool DoFlowAnalysis (FlowAnalysisContext fc) + { + fc.Report.Error (163, loc, "Control cannot fall through from one case label `{0}' to another", + label.GetSignatureForError ()); + + return true; + } + } + public Expression Expr; // @@ -4721,7 +4844,7 @@ namespace Mono.CSharp { } } - SwitchLabel FindLabel (Constant value) + public SwitchLabel FindLabel (Constant value) { SwitchLabel sl = null; @@ -4905,8 +5028,12 @@ namespace Mono.CSharp { base.MarkReachable (rc); + if (block.Statements.Count == 0) + return rc; + SwitchLabel constant_label = null; var constant = new_expr as Constant; + if (constant != null) { constant_label = FindLabel (constant) ?? case_default; if (constant_label == null) { @@ -4915,7 +5042,6 @@ namespace Mono.CSharp { } } - var switch_rc = rc; var section_rc = new Reachability (); SwitchLabel prev_label = null; @@ -4923,44 +5049,41 @@ namespace Mono.CSharp { var s = block.Statements[i]; var sl = s as SwitchLabel; - if (sl != null) { - if (!sl.SectionStart) { - sl.MarkReachable (section_rc); + if (sl != null && sl.SectionStart) { + // + // Section is marked already via constant switch or goto case + // + if (!sl.IsUnreachable) { + section_rc = new Reachability (); continue; } - if (prev_label == null) { - prev_label = sl; - switch_rc = Reachability.CreateUnreachable (); - - if (constant_label != null && sl != constant_label) - section_rc = Reachability.CreateUnreachable (); - - continue; + if (section_rc.IsUnreachable) { + section_rc = new Reachability (); + } else { + if (prev_label != null) { + sl.SectionStart = false; + s = new MissingBreak (prev_label); + s.MarkReachable (rc); + block.Statements.Insert (i - 1, s); + ++i; + } } - // - // Small trick, using unreachable flag for label means - // the label section does not fallthrough - // - prev_label.MarkReachable (section_rc); - prev_label = sl; - switch_rc &= section_rc; - section_rc = new Reachability (); - if (constant_label != null && sl != constant_label) + if (constant_label != null && constant_label != sl) section_rc = Reachability.CreateUnreachable (); - - continue; } section_rc = s.MarkReachable (section_rc); } - if (prev_label != null) { - prev_label.MarkReachable (section_rc); - switch_rc &= section_rc; + if (!section_rc.IsUnreachable && prev_label != null) { + prev_label.SectionStart = false; + var s = new MissingBreak (prev_label); + s.MarkReachable (rc); + block.Statements.Add (s); } // @@ -4976,7 +5099,7 @@ namespace Mono.CSharp { if (end_reachable) return rc; - return switch_rc; + return Reachability.CreateUnreachable (); } public void RegisterGotoCase (GotoCase gotoCase, Constant value) @@ -5150,8 +5273,23 @@ namespace Mono.CSharp { { if (value == null) { // - // Constant switch, we already done the work + // Constant switch, we've already done the work if there is only 1 label + // referenced // + int reachable = 0; + foreach (var sl in case_labels) { + if (sl.IsUnreachable) + continue; + + if (reachable++ > 0) { + var constant = (Constant) new_expr; + var constant_label = FindLabel (constant) ?? case_default; + + ec.Emit (OpCodes.Br, constant_label.GetILLabel (ec)); + break; + } + } + return; } @@ -6267,7 +6405,7 @@ namespace Mono.CSharp { } } - public void RegisterOutParametersCheck (DefiniteAssignmentBitSet vector) + public void RegisterForControlExitCheck (DefiniteAssignmentBitSet vector) { if (try_exit_dat == null) try_exit_dat = new List (); @@ -6320,7 +6458,7 @@ namespace Mono.CSharp { // executed before exit // foreach (var try_da_part in try_exit_dat) - fc.ParametersBlock.CheckOutParametersAssignment (fc, fc.DefiniteAssignment | try_da_part); + fc.ParametersBlock.CheckControlExit (fc, fc.DefiniteAssignment | try_da_part); try_exit_dat = null; } @@ -6607,10 +6745,12 @@ namespace Mono.CSharp { return; } - bc.Report.SymbolRelatedToPreviousError (type); - var loc = type_expr == null ? initializer.Location : type_expr.Location; - bc.Report.Error (1674, loc, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'", - type.GetSignatureForError ()); + if (type != InternalType.ErrorType) { + bc.Report.SymbolRelatedToPreviousError (type); + var loc = type_expr == null ? initializer.Location : type_expr.Location; + bc.Report.Error (1674, loc, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'", + type.GetSignatureForError ()); + } return; }