Merge pull request #900 from Blewzman/FixAggregateExceptionGetBaseException
[mono.git] / mcs / mcs / statement.cs
index b3043994dc578939a06dfabb58f5663e03496865..2bc9aed2c37c9a398c11dbbe5cdd7b4f4e14b4c2 100644 (file)
@@ -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<DefiniteAssignmentBitSet> end_reachability;
+               List<DefiniteAssignmentBitSet> 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<DefiniteAssignmentBitSet> ();
+                       if (end_reachable_das == null)
+                               end_reachable_das = new List<DefiniteAssignmentBitSet> ();
 
-                       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<string, object> 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<string, object> ();
+
+                                       foreach (var entry in pb.labels) {
+                                               var list = entry.Value as List<LabeledStatement>;
+
+                                               if (list != null) {
+                                                       var list_clone = new List<LabeledStatement> ();
+                                                       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<LabeledStatement> list = (List<LabeledStatement>) 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<string, object> names;
-               Dictionary<string, object> labels;
 
                List<ExplicitBlock> 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<LabeledStatement> list = (List<LabeledStatement>) value;
-                               for (int i = 0; i < list.Count; ++i) {
-                                       label = list[i];
-                                       if (label.Block == b.Original)
-                                               return label;
-                               }
-                       }
-                               
-                       return null;
-               }
-
                // <summary>
                //   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<DefiniteAssignmentBitSet> ();
@@ -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;
                                }