Merge pull request #5636 from BrzVlad/fix-xmm-scan
[mono.git] / mcs / mcs / statement.cs
index 10fc11219613f2b3a69c251bbcc78e4adf6e8605..0c02bf0562a271da6811188fd102ecf836f0986a 100644 (file)
@@ -269,11 +269,15 @@ namespace Mono.CSharp {
 
                        var da_false = new DefiniteAssignmentBitSet (fc.DefiniteAssignmentOnFalse);
 
-                       fc.DefiniteAssignment = fc.DefiniteAssignmentOnTrue;
+                       fc.BranchDefiniteAssignment (fc.DefiniteAssignmentOnTrue);
+                       var labels = fc.CopyLabelStack ();
 
                        var res = TrueStatement.FlowAnalysis (fc);
 
+                       fc.SetLabelStack (labels);
+
                        if (FalseStatement == null) {
+
                                var c = expr as Constant;
                                if (c != null && !c.IsDefaultValue)
                                        return true_returns;
@@ -288,14 +292,20 @@ namespace Mono.CSharp {
 
                        if (true_returns) {
                                fc.DefiniteAssignment = da_false;
-                               return FalseStatement.FlowAnalysis (fc);
+
+                               res = FalseStatement.FlowAnalysis (fc);
+                               fc.SetLabelStack (labels);
+                               return res;
                        }
 
                        var da_true = fc.DefiniteAssignment;
 
                        fc.DefiniteAssignment = da_false;
+
                        res &= FalseStatement.FlowAnalysis (fc);
 
+                       fc.SetLabelStack (labels);
+
                        if (!TrueStatement.IsUnreachable) {
                                if (false_returns || FalseStatement.IsUnreachable)
                                        fc.DefiniteAssignment = da_true;
@@ -548,6 +558,8 @@ namespace Mono.CSharp {
                                ec.Emit (OpCodes.Br, ec.LoopBegin);
                                ec.MarkLabel (while_loop);
 
+                               expr.EmitPrepare (ec);
+
                                Statement.Emit (ec);
                        
                                ec.MarkLabel (ec.LoopBegin);
@@ -566,9 +578,10 @@ namespace Mono.CSharp {
                {
                        expr.FlowAnalysisConditional (fc);
 
-                       fc.DefiniteAssignment = fc.DefiniteAssignmentOnTrue;
                        var da_false = new DefiniteAssignmentBitSet (fc.DefiniteAssignmentOnFalse);
 
+                       fc.BranchDefiniteAssignment (fc.DefiniteAssignmentOnTrue);
+
                        Statement.FlowAnalysis (fc);
 
                        //
@@ -1104,6 +1117,7 @@ namespace Mono.CSharp {
        public class Return : ExitStatement
        {
                Expression expr;
+               bool expr_returns;
 
                public Return (Expression expr, Location l)
                {
@@ -1258,16 +1272,38 @@ namespace Mono.CSharp {
                        if (expr == null)
                                return false;
 
+                       if (expr is ReferenceExpression && block_return_type.Kind != MemberKind.ByRef) {
+                               ec.Report.Error (8149, loc, "By-reference returns can only be used in methods that return by reference");
+                               return false;
+                       }
+
                        if (expr.Type != block_return_type && expr.Type != InternalType.ErrorType) {
-                               expr = Convert.ImplicitConversionRequired (ec, expr, block_return_type, loc);
+                               if (block_return_type.Kind == MemberKind.ByRef) {
+                                       var ref_expr = Expr as ReferenceExpression;
+                                       if (ref_expr == null) {
+                                               ec.Report.Error (8150, loc, "By-reference return is required when method returns by reference");
+                                               return false;
+                                       }
+
+                                       var byref_return = (ReferenceContainer)block_return_type;
 
-                               if (expr == null) {
-                                       if (am != null && block_return_type == ec.ReturnType) {
-                                               ec.Report.Error (1662, loc,
-                                                       "Cannot convert `{0}' to delegate type `{1}' because some of the return types in the block are not implicitly convertible to the delegate return type",
-                                                       am.ContainerType, am.GetSignatureForError ());
+                                       if (expr.Type != byref_return.Element) {
+                                               ec.Report.Error (8151, loc, "The return by reference expression must be of type `{0}' because this method returns by reference",
+                                                                                byref_return.GetSignatureForError ());
+                                               return false;
+                                       }
+                               } else {
+
+                                       expr = Convert.ImplicitConversionRequired (ec, expr, block_return_type, loc);
+
+                                       if (expr == null) {
+                                               if (am != null && block_return_type == ec.ReturnType) {
+                                                       ec.Report.Error (1662, loc,
+                                                               "Cannot convert `{0}' to delegate type `{1}' because some of the return types in the block are not implicitly convertible to the delegate return type",
+                                                               am.ContainerType, am.GetSignatureForError ());
+                                               }
+                                               return false;
                                        }
-                                       return false;
                                }
                        }
 
@@ -1291,11 +1327,7 @@ namespace Mono.CSharp {
                                                // Special case hoisted return value (happens in try/finally scenario)
                                                //
                                                if (ec.TryFinallyUnwind != null) {
-                                                       if (storey.HoistedReturnValue is VariableReference) {
-                                                               storey.HoistedReturnValue = ec.GetTemporaryField (storey.HoistedReturnValue.Type);
-                                                       }
-
-                                                       exit_label = TryFinally.EmitRedirectedReturn (ec, async_body);
+                                                       exit_label = TryFinally.EmitRedirectedReturn (ec, async_body, unwind_protect);
                                                }
 
                                                var async_return = (IAssignMethod)storey.HoistedReturnValue;
@@ -1305,7 +1337,7 @@ namespace Mono.CSharp {
                                                expr.Emit (ec);
 
                                                if (ec.TryFinallyUnwind != null)
-                                                       exit_label = TryFinally.EmitRedirectedReturn (ec, async_body);
+                                                       exit_label = TryFinally.EmitRedirectedReturn (ec, async_body, unwind_protect);
                                        }
 
                                        ec.Emit (OpCodes.Leave, exit_label);
@@ -1333,7 +1365,9 @@ namespace Mono.CSharp {
                        if (expr != null)
                                expr.FlowAnalysis (fc);
 
-                       base.DoFlowAnalysis (fc);
+                       if (!expr_returns)
+                               base.DoFlowAnalysis (fc);
+                       
                        return true;
                }
 
@@ -1346,6 +1380,12 @@ namespace Mono.CSharp {
                public override Reachability MarkReachable (Reachability rc)
                {
                        base.MarkReachable (rc);
+
+                       if (Expr != null) {
+                               rc = Expr.MarkReachable (rc);
+                               expr_returns = rc.IsUnreachable;
+                       }
+
                        return Reachability.CreateUnreachable ();
                }
 
@@ -1408,6 +1448,10 @@ namespace Mono.CSharp {
 
                protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
                {
+                       // Goto to unreachable label
+                       if (label == null)
+                               return true;
+
                        if (fc.AddReachedLabel (label))
                                return true;
 
@@ -1424,12 +1468,12 @@ namespace Mono.CSharp {
 
                        if (try_finally != null) {
                                if (try_finally.FinallyBlock.HasReachableClosingBrace) {
-                                       label.AddGotoReference (rc, false);
+                                       label.AddGotoReference (rc);
                                } else {
-                                       label.AddGotoReference (rc, true);
+                                       label = null;
                                }
                        } else {
-                               label.AddGotoReference (rc, false);
+                               label.AddGotoReference (rc);
                        }
 
                        return Reachability.CreateUnreachable ();
@@ -1442,14 +1486,15 @@ namespace Mono.CSharp {
 
                protected override void DoEmit (EmitContext ec)
                {
+                       // This should only happen for goto from try block to unrechable label
                        if (label == null)
-                               throw new InternalErrorException ("goto emitted before target resolved");
+                               return;
 
                        Label l = label.LabelTarget (ec);
 
                        if (ec.TryFinallyUnwind != null && IsLeavingFinally (label.Block)) {
                                var async_body = (AsyncInitializer) ec.CurrentAnonymousMethod;
-                               l = TryFinally.EmitRedirectedJump (ec, async_body, l, label.Block);
+                               l = TryFinally.EmitRedirectedJump (ec, async_body, l, label.Block, unwind_protect);
                        }
 
                        ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, l);
@@ -1478,7 +1523,6 @@ namespace Mono.CSharp {
                string name;
                bool defined;
                bool referenced;
-               bool finalTarget;
                Label label;
                Block block;
                
@@ -1525,9 +1569,6 @@ namespace Mono.CSharp {
                {
                        LabelTarget (ec);
                        ec.MarkLabel (label);
-
-                       if (finalTarget)
-                               ec.Emit (OpCodes.Br_S, label);
                }
 
                protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
@@ -1549,7 +1590,7 @@ namespace Mono.CSharp {
                        return rc;
                }
 
-               public void AddGotoReference (Reachability rc, bool finalTarget)
+               public void AddGotoReference (Reachability rc)
                {
                        if (referenced)
                                return;
@@ -1557,17 +1598,6 @@ namespace Mono.CSharp {
                        referenced = true;
                        MarkReachable (rc);
 
-                       //
-                       // Label is final target when goto jumps out of try block with
-                       // finally clause. In that case we need leave with target but in C#
-                       // terms the label is unreachable. Using finalTarget we emit
-                       // explicit label not just marker
-                       //
-                       if (finalTarget) {
-                               this.finalTarget = true;
-                               return;
-                       }
-
                        block.ScanGotoJump (this);
                }
 
@@ -1771,6 +1801,19 @@ namespace Mono.CSharp {
                        }
                }
 
+               public static Expression ConvertType (ResolveContext rc, Expression expr)
+               {
+                       var et = rc.BuiltinTypes.Exception;
+                       if (Convert.ImplicitConversionExists (rc, expr, et))
+                               expr = Convert.ImplicitConversion (rc, expr, et, expr.Location);
+                       else {
+                               rc.Report.Error (155, expr.Location, "The type caught or thrown must be derived from System.Exception");
+                               expr = EmptyCast.Create (expr, et);
+                       }
+
+                       return expr;
+               }
+
                public override bool Resolve (BlockContext ec)
                {
                        if (expr == null) {
@@ -1794,11 +1837,7 @@ namespace Mono.CSharp {
                        if (expr == null)
                                return false;
 
-                       var et = ec.BuiltinTypes.Exception;
-                       if (Convert.ImplicitConversionExists (ec, expr, et))
-                               expr = Convert.ImplicitConversion (ec, expr, et, loc);
-                       else
-                               ec.Report.Error (155, expr.Location, "The type caught or thrown must be derived from System.Exception");
+                       expr = ConvertType (ec, expr);
 
                        return true;
                }
@@ -1871,7 +1910,7 @@ namespace Mono.CSharp {
 
                        if (ec.TryFinallyUnwind != null) {
                                var async_body = (AsyncInitializer) ec.CurrentAnonymousMethod;
-                               l = TryFinally.EmitRedirectedJump (ec, async_body, l, enclosing_loop.Statement as Block);
+                               l = TryFinally.EmitRedirectedJump (ec, async_body, l, enclosing_loop.Statement as Block, unwind_protect);
                        }
 
                        ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, l);
@@ -1919,7 +1958,7 @@ namespace Mono.CSharp {
 
                        if (ec.TryFinallyUnwind != null) {
                                var async_body = (AsyncInitializer) ec.CurrentAnonymousMethod;
-                               l = TryFinally.EmitRedirectedJump (ec, async_body, l, enclosing_loop.Statement as Block);
+                               l = TryFinally.EmitRedirectedJump (ec, async_body, l, enclosing_loop.Statement as Block, unwind_protect);
                        }
 
                        ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, l);
@@ -2168,7 +2207,7 @@ namespace Mono.CSharp {
                                }
 
                                if (type == null) {
-                                       type = type_expr.ResolveAsType (bc);
+                                       type = ResolveTypeExpression (bc);
                                        if (type == null)
                                                return false;
 
@@ -2191,6 +2230,25 @@ namespace Mono.CSharp {
                        }
 
                        if (initializer != null) {
+                               if (li.IsByRef) {
+                                       if (!(initializer is ReferenceExpression)) {
+                                               bc.Report.Error (8172, loc, "Cannot initialize a by-reference variable `{0}' with a value", li.Name);
+                                               return false;
+                                       }
+
+                                       if (bc.CurrentAnonymousMethod is AsyncInitializer) {
+                                               bc.Report.Error (8177, loc, "Async methods cannot use by-reference variables");
+                                       } else if (bc.CurrentIterator != null) {
+                                               bc.Report.Error (8176, loc, "Iterators cannot use by-reference variables");
+                                       }
+
+                               } else {
+                                       if (initializer is ReferenceExpression) {
+                                               bc.Report.Error (8171, loc, "Cannot initialize a by-value variable `{0}' with a reference expression", li.Name);
+                                               return false;
+                                       }
+                               }
+
                                initializer = ResolveInitializer (bc, li, initializer);
                                // li.Variable.DefinitelyAssigned 
                        }
@@ -2220,6 +2278,11 @@ namespace Mono.CSharp {
                        return a.ResolveStatement (bc);
                }
 
+               protected virtual TypeSpec ResolveTypeExpression (BlockContext bc)
+               {
+                       return type_expr.ResolveAsType (bc);
+               }
+
                protected override void DoEmit (EmitContext ec)
                {
                        li.CreateBuilder (ec);
@@ -2255,11 +2318,8 @@ namespace Mono.CSharp {
 
                public override Reachability MarkReachable (Reachability rc)
                {
-                       var init = initializer as ExpressionStatement;
-                       if (init != null)
-                               init.MarkReachable (rc);
-
-                       return base.MarkReachable (rc);
+                       base.MarkReachable (rc);
+                       return initializer == null ? rc : initializer.MarkReachable (rc);
                }
 
                protected override void CloneTo (CloneContext clonectx, Statement target)
@@ -2294,6 +2354,9 @@ namespace Mono.CSharp {
 
                public override void Emit (EmitContext ec)
                {
+                       if (!Variable.IsUsed)
+                               ec.Report.Warning (219, 3, loc, "The constant `{0}' is never used", Variable.Name);
+                       
                        // Nothing to emit, not even sequence point
                }
 
@@ -2347,6 +2410,7 @@ namespace Mono.CSharp {
                        UsingVariable = 1 << 7,
                        IsLocked = 1 << 8,
                        SymbolFileHidden = 1 << 9,
+                       ByRef = 1 << 10,
 
                        ReadonlyMask = ForeachVariable | FixedVariable | UsingVariable
                }
@@ -2419,12 +2483,20 @@ namespace Mono.CSharp {
                        }
                }
 
+               public bool Created {
+                       get {
+                               return builder != null;
+                       }
+               }
+
                public bool IsDeclared {
                        get {
                                return type != null;
                        }
                }
 
+               public bool IsByRef => (flags & Flags.ByRef) != 0;
+
                public bool IsCompilerGenerated {
                        get {
                                return (flags & Flags.CompilerGenerated) != 0;
@@ -2452,10 +2524,19 @@ namespace Mono.CSharp {
                        }
                }
 
+               public bool IsUsed {
+                       get {
+                               return (flags & Flags.Used) != 0;
+                       }
+               }
+
                public bool IsFixed {
                        get {
                                return (flags & Flags.FixedVariable) != 0;
                        }
+                       set {
+                               flags = value ? flags | Flags.FixedVariable : flags & ~Flags.FixedVariable;
+                       }
                }
 
                bool INamedBlockVariable.IsParameter {
@@ -2518,10 +2599,15 @@ namespace Mono.CSharp {
                                throw new InternalErrorException ("Already created variable `{0}'", name);
                        }
 
-                       //
-                       // All fixed variabled are pinned, a slot has to be alocated
-                       //
-                       builder = ec.DeclareLocal (Type, IsFixed);
+                       if (IsByRef) {
+                               builder = ec.DeclareLocal (ReferenceContainer.MakeType (ec.Module, Type), IsFixed);
+                       } else {
+                               //
+                               // All fixed variabled are pinned, a slot has to be alocated
+                               //
+                               builder = ec.DeclareLocal(Type, IsFixed);
+                       }
+
                        if ((flags & Flags.SymbolFileHidden) == 0)
                                ec.DefineLocalVariable (name, builder);
                }
@@ -2538,8 +2624,10 @@ namespace Mono.CSharp {
 
                public Expression CreateReferenceExpression (ResolveContext rc, Location loc)
                {
-                       if (IsConstant && const_value != null)
+                       if (IsConstant && const_value != null) {
+                               SetIsUsed ();
                                return Constant.CreateConstantFromValue (Type, const_value.GetValue (), loc);
+                       }
 
                        return new LocalVariableReference (this, loc);
                }
@@ -2568,7 +2656,10 @@ namespace Mono.CSharp {
                        if ((flags & Flags.CompilerGenerated) != 0)
                                CreateBuilder (ec);
 
-                       ec.Emit (OpCodes.Ldloca, builder);
+                       if (IsByRef)
+                               ec.Emit (OpCodes.Ldloc, builder);
+                       else
+                               ec.Emit (OpCodes.Ldloca, builder);
                }
 
                public static string GetCompilerGeneratedName (Block block)
@@ -2668,6 +2759,7 @@ namespace Mono.CSharp {
                        AwaitBlock = 1 << 13,
                        FinallyBlock = 1 << 14,
                        CatchBlock = 1 << 15,
+                       HasReferenceToStoreyForInstanceLambdas = 1 << 16,
                        Iterator = 1 << 20,
                        NoFlowAnalysis = 1 << 21,
                        InitializationEmitted = 1 << 22
@@ -2989,18 +3081,30 @@ namespace Mono.CSharp {
                                if (end_unreachable) {
                                        bool after_goto_case = goto_flow_analysis && s is GotoCase;
 
-                                       for (++startIndex; startIndex < statements.Count; ++startIndex) {
-                                               s = statements[startIndex];
-                                               if (s is SwitchLabel) {
-                                                       if (!after_goto_case)
-                                                               s.FlowAnalysis (fc);
+                                       var f = s as TryFinally;
+                                       if (f != null && !f.FinallyBlock.HasReachableClosingBrace) {
+                                               //
+                                               // Special case for try-finally with unreachable code after
+                                               // finally block. Try block has to include leave opcode but there is
+                                               // no label to leave to after unreachable finally block closing
+                                               // brace. This sentinel ensures there is always IL instruction to
+                                               // leave to even if we know it'll never be reached.
+                                               //
+                                               statements.Insert (startIndex + 1, new SentinelStatement ());
+                                       } else {
+                                               for (++startIndex; startIndex < statements.Count; ++startIndex) {
+                                                       s = statements [startIndex];
+                                                       if (s is SwitchLabel) {
+                                                               if (!after_goto_case)
+                                                                       s.FlowAnalysis (fc);
 
-                                                       break;
-                                               }
+                                                               break;
+                                                       }
 
-                                               if (s.IsUnreachable) {
-                                                       s.FlowAnalysis (fc);
-                                                       statements [startIndex] = RewriteUnreachableStatement (s);
+                                                       if (s.IsUnreachable) {
+                                                               s.FlowAnalysis (fc);
+                                                               statements [startIndex] = RewriteUnreachableStatement (s);
+                                                       }
                                                }
                                        }
 
@@ -3040,7 +3144,7 @@ namespace Mono.CSharp {
                        // L:
                        //      v = 1;
 
-                       if (s is BlockVariable || s is EmptyStatement)
+                       if (s is BlockVariable || s is EmptyStatement || s is SentinelStatement)
                                return s;
 
                        return new EmptyStatement (s.loc);
@@ -3114,6 +3218,7 @@ namespace Mono.CSharp {
        public class ExplicitBlock : Block
        {
                protected AnonymousMethodStorey am_storey;
+               int debug_scope_index;
 
                public ExplicitBlock (Block parent, Location start, Location end)
                        : this (parent, (Flags) 0, start, end)
@@ -3221,8 +3326,11 @@ namespace Mono.CSharp {
 
                public override void Emit (EmitContext ec)
                {
-                       if (Parent != null)
-                               ec.BeginScope ();
+                       // TODO: It's needed only when scope has variable (normal or lifted)
+                       var scopeIndex = GetDebugSymbolScopeIndex ();
+                       if (scopeIndex > 0) {
+                               ec.BeginScope (scopeIndex);
+                       }
 
                        EmitScopeInitialization (ec);
 
@@ -3232,7 +3340,7 @@ namespace Mono.CSharp {
 
                        DoEmit (ec);
 
-                       if (Parent != null)
+                       if (scopeIndex > 0)
                                ec.EndScope ();
 
                        if (ec.EmitAccurateDebugInfo && HasReachableClosingBrace && !(this is ParametersBlock) &&
@@ -3253,6 +3361,7 @@ namespace Mono.CSharp {
                        //
                        storey.CreateContainer ();
                        storey.DefineContainer ();
+                       storey.ExpandBaseInterfaces ();
 
                        if (Original.Explicit.HasCapturedThis && Original.ParametersBlock.TopBlock.ThisReferencesFromChildrenBlock != null) {
 
@@ -3277,7 +3386,7 @@ namespace Mono.CSharp {
                                                        break;
                                        }
                                }
-                               
+
                                //
                                // We are the first storey on path and 'this' has to be hoisted
                                //
@@ -3345,7 +3454,7 @@ namespace Mono.CSharp {
 
                                                                //
                                                                // If we are state machine with no parent. We can hook into parent without additional
-                                                               // reference and capture this directly
+                                                               // reference and capture this directly
                                                                //
                                                                ExplicitBlock parent_storey_block = pb;
                                                                while (parent_storey_block.Parent != null) {
@@ -3367,7 +3476,7 @@ namespace Mono.CSharp {
                                                                var parent_this_block = pb;
                                                                while (parent_this_block.Parent != null) {
                                                                        parent_this_block = parent_this_block.Parent.ParametersBlock;
-                                                                       if (parent_this_block.StateMachine != null) {
+                                                                       if (parent_this_block.StateMachine != null && parent_this_block.StateMachine.HoistedThis != null) {
                                                                                break;
                                                                        }
                                                                }
@@ -3424,6 +3533,19 @@ namespace Mono.CSharp {
                        storey.Parent.PartialContainer.AddCompilerGeneratedClass (storey);
                }
 
+               public void DisableDebugScopeIndex ()
+               {
+                       debug_scope_index = -1;
+               }
+
+               public virtual int GetDebugSymbolScopeIndex ()
+               {
+                       if (debug_scope_index == 0)
+                               debug_scope_index = ++ParametersBlock.debug_scope_index;
+
+                       return debug_scope_index;
+               }
+
                public void RegisterAsyncAwait ()
                {
                        var block = this;
@@ -3654,6 +3776,15 @@ namespace Mono.CSharp {
 
                #region Properties
 
+               public bool HasReferenceToStoreyForInstanceLambdas {
+                       get {
+                               return (flags & Flags.HasReferenceToStoreyForInstanceLambdas) != 0;
+                       }
+                       set {
+                               flags = value ? flags | Flags.HasReferenceToStoreyForInstanceLambdas : flags & ~Flags.HasReferenceToStoreyForInstanceLambdas;
+                       }
+               }
+
                public bool IsAsync {
                        get {
                                return (flags & Flags.HasAsyncModifier) != 0;
@@ -3815,6 +3946,11 @@ namespace Mono.CSharp {
                        return res;
                }
 
+               public override int GetDebugSymbolScopeIndex ()
+               {
+                       return 0;
+               }
+
                public LabeledStatement GetLabel (string name, Block block)
                {
                        //
@@ -3876,8 +4012,10 @@ namespace Mono.CSharp {
                        return new ParameterReference (parameter_info[index], loc);
                }
 
-               public Statement PerformClone ()
+               public Statement PerformClone (ref HashSet<LocalVariable> undeclaredVariables)
                {
+                       undeclaredVariables = TopBlock.GetUndeclaredVariables ();
+
                        CloneContext clonectx = new CloneContext ();
                        return Clone (clonectx);
                }
@@ -4391,6 +4529,63 @@ namespace Mono.CSharp {
                        base.CheckControlExit (fc, dat);
                }
 
+               public HashSet<LocalVariable> GetUndeclaredVariables ()
+               {
+                       if (names == null)
+                               return null;
+
+                       HashSet<LocalVariable> variables = null;
+
+                       foreach (var entry in names) {
+                               var complex = entry.Value as List<INamedBlockVariable>;
+                               if (complex != null) {
+                                       foreach (var centry in complex) {
+                                               if (IsUndeclaredVariable (centry)) {
+                                                       if (variables == null)
+                                                               variables = new HashSet<LocalVariable> ();
+
+                                                       variables.Add ((LocalVariable) centry);
+                                               }
+                                       }
+                               } else if (IsUndeclaredVariable ((INamedBlockVariable)entry.Value)) {
+                                       if (variables == null)
+                                               variables = new HashSet<LocalVariable> ();
+
+                                       variables.Add ((LocalVariable)entry.Value);                                     
+                               }
+                       }
+
+                       return variables;
+               }
+
+               static bool IsUndeclaredVariable (INamedBlockVariable namedBlockVariable)
+               {
+                       var lv = namedBlockVariable as LocalVariable;
+                       return lv != null && !lv.IsDeclared;
+               }
+
+               public void SetUndeclaredVariables (HashSet<LocalVariable> undeclaredVariables)
+               {
+                       if (names == null)
+                               return;
+                       
+                       foreach (var entry in names) {
+                               var complex = entry.Value as List<INamedBlockVariable>;
+                               if (complex != null) {
+                                       foreach (var centry in complex) {
+                                               var lv = centry as LocalVariable;
+                                               if (lv != null && undeclaredVariables.Contains (lv)) {
+                                                       lv.Type = null;
+                                               }
+                                       }
+                               } else {
+                                       var lv = entry.Value as LocalVariable;
+                                       if (lv != null && undeclaredVariables.Contains (lv))
+                                               lv.Type = null;
+                               }
+                       }
+               }
+
                public override void Emit (EmitContext ec)
                {
                        if (Report.Errors > 0)
@@ -5307,18 +5502,30 @@ namespace Mono.CSharp {
                                                continue;
                                        }
 
-                                       if (constant_label != null && constant_label != sl)
+                                       if (section_rc.IsUnreachable) {
+                                               //
+                                               // Common case. Previous label section end is unreachable as
+                                               // it ends with break, return, etc. For next section revert
+                                               // to reachable again unless we have constant switch block
+                                               //
+                                               section_rc = constant_label != null && constant_label != sl ?
+                                                       Reachability.CreateUnreachable () :
+                                                       new Reachability ();
+                                       } else if (prev_label != null) {
+                                               //
+                                               // Error case as control cannot fall through from one case label
+                                               //
+                                               sl.SectionStart = false;
+                                               s = new MissingBreak (prev_label);
+                                               s.MarkReachable (rc);
+                                               block.Statements.Insert (i - 1, s);
+                                               ++i;
+                                       } else if (constant_label != null && constant_label != sl) {
+                                               //
+                                               // Special case for the first unreachable label in constant
+                                               // switch block
+                                               //
                                                section_rc = Reachability.CreateUnreachable ();
-                                       else 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;
-                                               }
                                        }
 
                                        prev_label = sl;
@@ -5806,7 +6013,7 @@ namespace Mono.CSharp {
                protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
                {
                        var res = stmt.FlowAnalysis (fc);
-                       parent = null;
+                       parent_try_block = null;
                        return res;
                }
 
@@ -5826,14 +6033,18 @@ namespace Mono.CSharp {
                {
                        bool ok;
 
-                       parent = bc.CurrentTryBlock;
+                       parent_try_block = bc.CurrentTryBlock;
                        bc.CurrentTryBlock = this;
 
-                       using (bc.Set (ResolveContext.Options.TryScope)) {
+                       if (stmt is TryCatch) {
                                ok = stmt.Resolve (bc);
+                       } else {
+                               using (bc.Set (ResolveContext.Options.TryScope)) {
+                                       ok = stmt.Resolve (bc);
+                               }
                        }
 
-                       bc.CurrentTryBlock = parent;
+                       bc.CurrentTryBlock = parent_try_block;
 
                        //
                        // Finally block inside iterator is called from MoveNext and
@@ -5859,18 +6070,14 @@ namespace Mono.CSharp {
        {
                protected List<ResumableStatement> resume_points;
                protected int first_resume_pc;
-               protected ExceptionStatement parent;
+               protected ExceptionStatement parent_try_block;
+               protected int first_catch_resume_pc = -1;
 
                protected ExceptionStatement (Location loc)
                {
                        this.loc = loc;
                }
 
-               protected virtual void EmitBeginException (EmitContext ec)
-               {
-                       ec.BeginExceptionBlock ();
-               }
-
                protected virtual void EmitTryBodyPrepare (EmitContext ec)
                {
                        StateMachineInitializer state_machine = null;
@@ -5881,10 +6088,37 @@ namespace Mono.CSharp {
                                ec.Emit (OpCodes.Stloc, state_machine.CurrentPC);
                        }
 
-                       EmitBeginException (ec);
+                       //
+                       // The resume points in catch section when this is try-catch-finally
+                       //
+                       if (IsRewrittenTryCatchFinally ()) {
+                               ec.BeginExceptionBlock ();
 
-                       if (resume_points != null) {
-                               ec.MarkLabel (resume_point);
+                               if (first_catch_resume_pc >= 0) {
+
+                                       ec.MarkLabel (resume_point);
+
+                                       // For normal control flow, we want to fall-through the Switch
+                                       // So, we use CurrentPC rather than the $PC field, and initialize it to an outside value above
+                                       ec.Emit (OpCodes.Ldloc, state_machine.CurrentPC);
+                                       ec.EmitInt (first_resume_pc + first_catch_resume_pc);
+                                       ec.Emit (OpCodes.Sub);
+
+                                       var labels = new Label [resume_points.Count - first_catch_resume_pc];
+                                       for (int i = 0; i < labels.Length; ++i)
+                                               labels [i] = resume_points [i + first_catch_resume_pc].PrepareForEmit (ec);
+                                       ec.Emit (OpCodes.Switch, labels);
+                               }
+                       }
+
+                       ec.BeginExceptionBlock ();
+
+                       //
+                       // The resume points for try section
+                       //
+                       if (resume_points != null && first_catch_resume_pc != 0) {
+                               if (first_catch_resume_pc < 0)
+                                       ec.MarkLabel (resume_point);
 
                                // For normal control flow, we want to fall-through the Switch
                                // So, we use CurrentPC rather than the $PC field, and initialize it to an outside value above
@@ -5892,21 +6126,30 @@ namespace Mono.CSharp {
                                ec.EmitInt (first_resume_pc);
                                ec.Emit (OpCodes.Sub);
 
-                               Label[] labels = new Label[resume_points.Count];
-                               for (int i = 0; i < resume_points.Count; ++i)
+                               var labels = new Label [first_catch_resume_pc > 0 ? first_catch_resume_pc : resume_points.Count];
+                               for (int i = 0; i < labels.Length; ++i)
                                        labels[i] = resume_points[i].PrepareForEmit (ec);
                                ec.Emit (OpCodes.Switch, labels);
                        }
                }
 
-               public virtual int AddResumePoint (ResumableStatement stmt, int pc, StateMachineInitializer stateMachine)
+               bool IsRewrittenTryCatchFinally ()
                {
-                       if (parent != null) {
-                               // TODO: MOVE to virtual TryCatch
-                               var tc = this as TryCatch;
-                               var s = tc != null && tc.IsTryCatchFinally ? stmt : this;
+                       var tf = this as TryFinally;
+                       if (tf == null)
+                               return false;
 
-                               pc = parent.AddResumePoint (s, pc, stateMachine);
+                       var tc = tf.Statement as TryCatch;
+                       if (tc == null)
+                               return false;
+
+                       return tf.FinallyBlock.HasAwait || tc.HasClauseWithAwait;
+               }
+
+               public int AddResumePoint (ResumableStatement stmt, int pc, StateMachineInitializer stateMachine, TryCatch catchBlock)
+               {
+                       if (parent_try_block != null) {
+                               pc = parent_try_block.AddResumePoint (this, pc, stateMachine, catchBlock);
                        } else {
                                pc = stateMachine.AddResumePoint (this);
                        }
@@ -5919,6 +6162,11 @@ namespace Mono.CSharp {
                        if (pc != first_resume_pc + resume_points.Count)
                                throw new InternalErrorException ("missed an intervening AddResumePoint?");
 
+                       var tf = this as TryFinally;
+                       if (tf != null && tf.Statement == catchBlock && first_catch_resume_pc < 0) {
+                               first_catch_resume_pc = resume_points.Count;
+                       }
+
                        resume_points.Add (stmt);
                        return pc;
                }
@@ -6190,7 +6438,7 @@ namespace Mono.CSharp {
                public override bool Resolve (BlockContext ec)
                {
                        if (ec.CurrentIterator != null)
-                               ec.Report.Error (1629, loc, "Unsafe code may not appear in iterators");
+                               Expression.UnsafeInsideIteratorError (ec, loc);
 
                        using (ec.Set (ResolveContext.Options.UnsafeScope))
                                return Block.Resolve (ec);
@@ -6290,6 +6538,7 @@ namespace Mono.CSharp {
                                        LocalVariable.Flags.FixedVariable | LocalVariable.Flags.CompilerGenerated | LocalVariable.Flags.Used,
                                        vi.Location);
                                pinned_string.Type = rc.BuiltinTypes.String;
+                               vi.IsFixed = false;
 
                                eclass = ExprClass.Variable;
                                type = rc.BuiltinTypes.Int;
@@ -6829,7 +7078,7 @@ namespace Mono.CSharp {
        {
                ExplicitBlock fini;
                List<DefiniteAssignmentBitSet> try_exit_dat;
-               List<Label> redirected_jumps;
+               List<Tuple<Label, bool>> redirected_jumps;
                Label? start_fin_label;
 
                public TryFinally (Statement stmt, ExplicitBlock fini, Location loc)
@@ -6864,14 +7113,6 @@ namespace Mono.CSharp {
                        return ok;
                }
 
-               protected override void EmitBeginException (EmitContext ec)
-               {
-                       if (fini.HasAwait && stmt is TryCatch)
-                               ec.BeginExceptionBlock ();
-
-                       base.EmitBeginException (ec);
-               }
-
                protected override void EmitTryBody (EmitContext ec)
                {
                        if (fini.HasAwait) {
@@ -6881,7 +7122,7 @@ namespace Mono.CSharp {
                                ec.TryFinallyUnwind.Add (this);
                                stmt.Emit (ec);
 
-                               if (stmt is TryCatch)
+                               if (first_catch_resume_pc < 0 && stmt is TryCatch)
                                        ec.EndExceptionBlock ();
 
                                ec.TryFinallyUnwind.Remove (this);
@@ -6924,6 +7165,7 @@ namespace Mono.CSharp {
                        ec.Emit (OpCodes.Stloc, temp);
 
                        var exception_field = ec.GetTemporaryField (type);
+                       exception_field.AutomaticallyReuse = false;
                        ec.EmitThis ();
                        ec.Emit (OpCodes.Ldloc, temp);
                        exception_field.EmitAssignFromStack (ec);
@@ -6947,7 +7189,7 @@ namespace Mono.CSharp {
                        ec.Emit (OpCodes.Throw);
                        ec.MarkLabel (skip_throw);
 
-                       exception_field.IsAvailableForReuse = true;
+                       exception_field.PrepareCleanup (ec);
 
                        EmitUnwindFinallyTable (ec);
                }
@@ -6962,7 +7204,7 @@ namespace Mono.CSharp {
                        return false;
                }
 
-               public static Label EmitRedirectedJump (EmitContext ec, AsyncInitializer initializer, Label label, Block labelBlock)
+               public static Label EmitRedirectedJump (EmitContext ec, AsyncInitializer initializer, Label label, Block labelBlock, bool unwindProtect)
                {
                        int idx;
                        if (labelBlock != null) {
@@ -6982,7 +7224,7 @@ namespace Mono.CSharp {
                                if (labelBlock != null && !fin.IsParentBlock (labelBlock))
                                        break;
 
-                               fin.EmitRedirectedExit (ec, label, initializer, set_return_state);
+                               fin.EmitRedirectedExit (ec, label, initializer, set_return_state, unwindProtect);
                                set_return_state = false;
 
                                if (fin.start_fin_label == null) {
@@ -6995,26 +7237,26 @@ namespace Mono.CSharp {
                        return label;
                }
 
-               public static Label EmitRedirectedReturn (EmitContext ec, AsyncInitializer initializer)
+               public static Label EmitRedirectedReturn (EmitContext ec, AsyncInitializer initializer, bool unwindProtect)
                {
-                       return EmitRedirectedJump (ec, initializer, initializer.BodyEnd, null);
+                       return EmitRedirectedJump (ec, initializer, initializer.BodyEnd, null, unwindProtect);
                }
 
-               void EmitRedirectedExit (EmitContext ec, Label label, AsyncInitializer initializer, bool setReturnState)
+               void EmitRedirectedExit (EmitContext ec, Label label, AsyncInitializer initializer, bool setReturnState, bool unwindProtect)
                {
                        if (redirected_jumps == null) {
-                               redirected_jumps = new List<Label> ();
+                               redirected_jumps = new List<Tuple<Label, bool>> ();
 
                                // Add fallthrough label
-                               redirected_jumps.Add (ec.DefineLabel ());
+                               redirected_jumps.Add (Tuple.Create (ec.DefineLabel (), false));
 
                                if (setReturnState)
                                        initializer.HoistedReturnState = ec.GetTemporaryField (ec.Module.Compiler.BuiltinTypes.Int, true);
                        }
 
-                       int index = redirected_jumps.IndexOf (label);
+                       int index = redirected_jumps.FindIndex (l => l.Item1 == label);
                        if (index < 0) {
-                               redirected_jumps.Add (label);
+                               redirected_jumps.Add (Tuple.Create (label, unwindProtect));
                                index = redirected_jumps.Count - 1;
                        }
 
@@ -7038,10 +7280,34 @@ namespace Mono.CSharp {
 
                        var initializer = (AsyncInitializer)ec.CurrentAnonymousMethod;
                        initializer.HoistedReturnState.EmitLoad (ec);
-                       ec.Emit (OpCodes.Switch, redirected_jumps.ToArray ());
+
+                       var jumps_table = new Label [redirected_jumps.Count];
+                       List<Tuple<Label, Label>> leave_redirect = null;
+                       for (int i = 0; i < jumps_table.Length; ++i) {
+                               var val = redirected_jumps [i];
+
+                               if (val.Item2) {
+                                       if (leave_redirect == null)
+                                               leave_redirect = new List<Tuple<Label, Label>> ();
+                                       var label = ec.DefineLabel ();
+                                       leave_redirect.Add (Tuple.Create (label, val.Item1));
+                                       jumps_table [i] = label;
+                               } else {
+                                       jumps_table [i] = val.Item1;
+                               }
+                       }
+
+                       ec.Emit (OpCodes.Switch, jumps_table);
+
+                       if (leave_redirect != null) {
+                               foreach (var entry in leave_redirect) {
+                                       ec.MarkLabel (entry.Item1);
+                                       ec.Emit (OpCodes.Leave, entry.Item2);
+                               }
+                       }
 
                        // Mark fallthrough label
-                       ec.MarkLabel (redirected_jumps [0]);
+                       ec.MarkLabel (jumps_table [0]);
                }
 
                protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
@@ -7121,6 +7387,12 @@ namespace Mono.CSharp {
                        }
                }
 
+               public bool HasClauseWithAwait {
+                       get {
+                               return catch_sm != null;
+                       }
+               }
+
                public bool IsTryCatchFinally {
                        get {
                                return inside_try_finally;
@@ -7132,7 +7404,8 @@ namespace Mono.CSharp {
                        bool ok;
 
                        using (bc.Set (ResolveContext.Options.TryScope)) {
-                               parent = bc.CurrentTryBlock;
+
+                               parent_try_block = bc.CurrentTryBlock;
 
                                if (IsTryCatchFinally) {
                                        ok = Block.Resolve (bc);
@@ -7140,11 +7413,14 @@ namespace Mono.CSharp {
                                        using (bc.Set (ResolveContext.Options.TryWithCatchScope)) {
                                                bc.CurrentTryBlock = this;
                                                ok = Block.Resolve (bc);
-                                               bc.CurrentTryBlock = parent;
+                                               bc.CurrentTryBlock = parent_try_block;
                                        }
                                }
                        }
 
+                       var prev_catch = bc.CurrentTryCatch;
+                       bc.CurrentTryCatch = this;
+
                        for (int i = 0; i < clauses.Count; ++i) {
                                var c = clauses[i];
 
@@ -7203,6 +7479,8 @@ namespace Mono.CSharp {
                                }
                        }
 
+                       bc.CurrentTryCatch = prev_catch;
+
                        return base.Resolve (bc) && ok;
                }
 
@@ -7235,10 +7513,12 @@ namespace Mono.CSharp {
                                }
                        }
 
-                       if (!inside_try_finally)
+                       if (state_variable == null) {
+                               if (!inside_try_finally)
+                                       ec.EndExceptionBlock ();
+                       } else {
                                ec.EndExceptionBlock ();
 
-                       if (state_variable != null) {
                                ec.Emit (OpCodes.Ldloc, state_variable);
 
                                var labels = new Label [catch_sm.Count + 1];
@@ -7260,6 +7540,10 @@ namespace Mono.CSharp {
                                                ec.Emit (OpCodes.Br, end);
 
                                        ec.MarkLabel (labels [i + 1]);
+
+                                       ec.EmitInt (0);
+                                       ec.Emit (OpCodes.Stloc, state_variable);
+
                                        c = catch_sm [i];
                                        ec.AsyncThrowVariable = c.Variable;
                                        c.Block.Emit (ec);
@@ -7290,7 +7574,7 @@ namespace Mono.CSharp {
                        }
 
                        fc.DefiniteAssignment = try_fc ?? start_fc;
-                       parent = null;
+                       parent_try_block = null;
                        return res;
                }
 
@@ -7721,7 +8005,11 @@ namespace Mono.CSharp {
 
                                for_each.variable.Type = var_type;
 
+                               var prev_block = ec.CurrentBlock;
+                               ec.CurrentBlock = variables_block;
                                var variable_ref = new LocalVariableReference (for_each.variable, loc).Resolve (ec);
+                               ec.CurrentBlock = prev_block;
+
                                if (variable_ref == null)
                                        return false;
 
@@ -8010,7 +8298,10 @@ namespace Mono.CSharp {
                                                return false;
                                }
 
+                               var prev_block = ec.CurrentBlock;
+                               ec.CurrentBlock = for_each.variable.Block;
                                var variable_ref = new LocalVariableReference (variable, loc).Resolve (ec);
+                               ec.CurrentBlock = prev_block;
                                if (variable_ref == null)
                                        return false;
 
@@ -8167,15 +8458,14 @@ namespace Mono.CSharp {
                        ec.LoopBegin = ec.DefineLabel ();
                        ec.LoopEnd = ec.DefineLabel ();
 
-                       if (!(Statement is Block))
-                               ec.BeginCompilerScope ();
+                       ec.BeginCompilerScope (variable.Block.Explicit.GetDebugSymbolScopeIndex ());
+                       body.Explicit.DisableDebugScopeIndex ();
 
                        variable.CreateBuilder (ec);
 
                        Statement.Emit (ec);
 
-                       if (!(Statement is Block))
-                               ec.EndScope ();
+                       ec.EndScope ();
 
                        ec.LoopBegin = old_begin;
                        ec.LoopEnd = old_end;
@@ -8206,4 +8496,23 @@ namespace Mono.CSharp {
                        return visitor.Visit (this);
                }
        }
+
+       class SentinelStatement: Statement
+       {
+               protected override void CloneTo (CloneContext clonectx, Statement target)
+               {
+               }
+
+               protected override void DoEmit (EmitContext ec)
+               {
+                       var l = ec.DefineLabel ();
+                       ec.MarkLabel (l);
+                       ec.Emit (OpCodes.Br_S, l);
+               }
+
+               protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
+               {
+                       throw new NotImplementedException ();
+               }
+       }
 }