Merge pull request #2200 from xmcclure/image-audit-oops
[mono.git] / mcs / mcs / statement.cs
index 66b56bfe24eba36aa8d32d44f1ca66c8b22d67de..ba58d1f1380ebbb95642eab2d2d03541b839967e 100644 (file)
@@ -1222,7 +1222,7 @@ namespace Mono.CSharp {
                                                //
                                                // The return type is actually Task<T> type argument
                                                //
-                                               if (expr.Type == async_type) {
+                                               if (expr.Type == async_type && async_type.TypeArguments [0] != ec.Module.PredefinedTypes.Task.TypeSpec) {
                                                        ec.Report.Error (4016, loc,
                                                                "`{0}': The return expression type of async method must be `{1}' rather than `Task<{1}>'",
                                                                ec.GetSignatureForError (), async_type.TypeArguments[0].GetSignatureForError ());
@@ -1408,6 +1408,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 +1428,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,8 +1446,9 @@ 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);
 
@@ -1478,7 +1483,6 @@ namespace Mono.CSharp {
                string name;
                bool defined;
                bool referenced;
-               bool finalTarget;
                Label label;
                Block block;
                
@@ -1525,9 +1529,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 +1550,7 @@ namespace Mono.CSharp {
                        return rc;
                }
 
-               public void AddGotoReference (Reachability rc, bool finalTarget)
+               public void AddGotoReference (Reachability rc)
                {
                        if (referenced)
                                return;
@@ -1557,17 +1558,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);
                }
 
@@ -2129,7 +2119,7 @@ namespace Mono.CSharp {
                                // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
                                // same name exists or as a keyword when no type was found
                                //
-                               if (vexpr != null && !vexpr.IsPossibleTypeOrNamespace (bc)) {
+                               if (vexpr != null && !vexpr.IsPossibleType (bc)) {
                                        if (bc.Module.Compiler.Settings.Version < LanguageVersion.V_3)
                                                bc.Report.FeatureIsNotAvailable (bc.Module.Compiler, loc, "implicitly typed local variable");
 
@@ -2346,6 +2336,7 @@ namespace Mono.CSharp {
                        FixedVariable = 1 << 6,
                        UsingVariable = 1 << 7,
                        IsLocked = 1 << 8,
+                       SymbolFileHidden = 1 << 9,
 
                        ReadonlyMask = ForeachVariable | FixedVariable | UsingVariable
                }
@@ -2455,6 +2446,9 @@ namespace Mono.CSharp {
                        get {
                                return (flags & Flags.FixedVariable) != 0;
                        }
+                       set {
+                               flags = value ? flags | Flags.FixedVariable : flags & ~Flags.FixedVariable;
+                       }
                }
 
                bool INamedBlockVariable.IsParameter {
@@ -2521,13 +2515,16 @@ namespace Mono.CSharp {
                        // All fixed variabled are pinned, a slot has to be alocated
                        //
                        builder = ec.DeclareLocal (Type, IsFixed);
-                       if (!ec.HasSet (BuilderContext.Options.OmitDebugInfo) && (flags & Flags.CompilerGenerated) == 0)
+                       if ((flags & Flags.SymbolFileHidden) == 0)
                                ec.DefineLocalVariable (name, builder);
                }
 
-               public static LocalVariable CreateCompilerGenerated (TypeSpec type, Block block, Location loc)
+               public static LocalVariable CreateCompilerGenerated (TypeSpec type, Block block, Location loc, bool writeToSymbolFile = false)
                {
                        LocalVariable li = new LocalVariable (block, GetCompilerGeneratedName (block), Flags.CompilerGenerated | Flags.Used, loc);
+                       if (!writeToSymbolFile)
+                               li.flags |= Flags.SymbolFileHidden;
+                       
                        li.Type = type;
                        return li;
                }
@@ -2985,18 +2982,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);
+                                                       }
                                                }
                                        }
 
@@ -3036,7 +3045,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);
@@ -3352,12 +3361,26 @@ namespace Mono.CSharp {
                                                                }
 
                                                                if (parent_storey_block.AnonymousMethodStorey == null) {
-                                                                       pb.StateMachine.AddCapturedThisField (ec, null);
-                                                                       b.HasCapturedThis = true;
+                                                                       if (pb.StateMachine.HoistedThis == null) {
+                                                                               pb.StateMachine.AddCapturedThisField (ec, null);
+                                                                               b.HasCapturedThis = true;
+                                                                       }
+
                                                                        continue;
                                                                }
 
-                                                               pb.StateMachine.AddParentStoreyReference (ec, storey);
+                                                               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 && parent_this_block.StateMachine.HoistedThis != null) {
+                                                                               break;
+                                                                       }
+                                                               }
+
+                                                               //
+                                                               // Add reference to closest storey which holds captured this
+                                                               //
+                                                               pb.StateMachine.AddParentStoreyReference (ec, parent_this_block.StateMachine ?? storey);
                                                        }
 
                                                        //
@@ -5848,6 +5871,11 @@ namespace Mono.CSharp {
                        this.loc = loc;
                }
 
+               protected virtual void EmitBeginException (EmitContext ec)
+               {
+                       ec.BeginExceptionBlock ();
+               }
+
                protected virtual void EmitTryBodyPrepare (EmitContext ec)
                {
                        StateMachineInitializer state_machine = null;
@@ -5858,7 +5886,7 @@ namespace Mono.CSharp {
                                ec.Emit (OpCodes.Stloc, state_machine.CurrentPC);
                        }
 
-                       ec.BeginExceptionBlock ();
+                       EmitBeginException (ec);
 
                        if (resume_points != null) {
                                ec.MarkLabel (resume_point);
@@ -6225,9 +6253,9 @@ namespace Mono.CSharp {
                        }
                }
 
-               class ExpressionEmitter : Emitter {
-                       public ExpressionEmitter (Expression converted, LocalVariable li) :
-                               base (converted, li)
+               sealed class ExpressionEmitter : Emitter {
+                       public ExpressionEmitter (Expression converted, LocalVariable li)
+                               base (converted, li)
                        {
                        }
 
@@ -6267,6 +6295,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;
@@ -6325,8 +6354,9 @@ namespace Mono.CSharp {
                                //
                                // Case 1: Array
                                //
-                               if (res.Type.IsArray) {
-                                       TypeSpec array_type = TypeManager.GetElementType (res.Type);
+                               var ac = res.Type as ArrayContainer;
+                               if (ac != null) {
+                                       TypeSpec array_type = ac.Element;
 
                                        //
                                        // Provided that array_type is unmanaged,
@@ -6334,6 +6364,15 @@ namespace Mono.CSharp {
                                        if (!TypeManager.VerifyUnmanaged (bc.Module, array_type, loc))
                                                return null;
 
+                                       Expression res_init;
+                                       if (ExpressionAnalyzer.IsInexpensiveLoad (res)) {
+                                               res_init = res;
+                                       } else {
+                                               var expr_variable = LocalVariable.CreateCompilerGenerated (ac, bc.CurrentBlock, loc);
+                                               res_init = new CompilerAssign (expr_variable.CreateReferenceExpression (bc, loc), res, loc);
+                                               res = expr_variable.CreateReferenceExpression (bc, loc);
+                                       }
+
                                        //
                                        // and T* is implicitly convertible to the
                                        // pointer type given in the fixed statement.
@@ -6348,7 +6387,7 @@ namespace Mono.CSharp {
                                        // fixed (T* e_ptr = (e == null || e.Length == 0) ? null : converted [0])
                                        //
                                        converted = new Conditional (new BooleanExpression (new Binary (Binary.Operator.LogicalOr,
-                                               new Binary (Binary.Operator.Equality, res, new NullLiteral (loc)),
+                                               new Binary (Binary.Operator.Equality, res_init, new NullLiteral (loc)),
                                                new Binary (Binary.Operator.Equality, new MemberAccess (res, "Length"), new IntConstant (bc.BuiltinTypes, 0, loc)))),
                                                        new NullLiteral (loc),
                                                        converted, loc);
@@ -6831,6 +6870,14 @@ 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) {
@@ -6839,6 +6886,10 @@ namespace Mono.CSharp {
 
                                ec.TryFinallyUnwind.Add (this);
                                stmt.Emit (ec);
+
+                               if (stmt is TryCatch)
+                                       ec.EndExceptionBlock ();
+
                                ec.TryFinallyUnwind.Remove (this);
 
                                if (start_fin_label != null)
@@ -8161,4 +8212,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 ();
+               }
+       }
 }