Merge pull request #2200 from xmcclure/image-audit-oops
[mono.git] / mcs / mcs / statement.cs
index bee698b231ad966ca805fc5e84aeb1d66e2d5d13..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;
                }
@@ -2914,9 +2911,7 @@ namespace Mono.CSharp {
 
                                if (!s.Resolve (bc)) {
                                        ok = false;
-                                       if (!bc.IsInProbingMode)
-                                               statements [ix] = new EmptyStatement (s.loc);
-
+                                       statements [ix] = new EmptyStatement (s.loc);
                                        continue;
                                }
                        }
@@ -2987,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);
+                                                       }
                                                }
                                        }
 
@@ -3038,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);
@@ -3354,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);
                                                        }
 
                                                        //
@@ -5850,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;
@@ -5860,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);
@@ -5933,7 +5959,7 @@ namespace Mono.CSharp {
                        if (expr == null)
                                return false;
 
-                       if (!TypeSpec.IsReferenceType (expr.Type)) {
+                       if (!TypeSpec.IsReferenceType (expr.Type) && expr.Type != InternalType.ErrorType) {
                                ec.Report.Error (185, loc,
                                        "`{0}' is not a reference type as required by the lock statement",
                                        expr.Type.GetSignatureForError ());
@@ -6227,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)
                        {
                        }
 
@@ -6269,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;
@@ -6320,32 +6347,16 @@ namespace Mono.CSharp {
                                        return null;
                                }
 
-                               //
-                               // The rules for the possible declarators are pretty wise,
-                               // but the production on the grammar is more concise.
-                               //
-                               // So we have to enforce these rules here.
-                               //
-                               // We do not resolve before doing the case 1 test,
-                               // because the grammar is explicit in that the token &
-                               // is present, so we need to test for this particular case.
-                               //
-
-                               if (initializer is Cast) {
-                                       bc.Report.Error (254, initializer.Location, "The right hand side of a fixed statement assignment may not be a cast expression");
-                                       return null;
-                               }
-
-                               initializer = initializer.Resolve (bc);
-
-                               if (initializer == null)
+                               var res = initializer.Resolve (bc);
+                               if (res == null)
                                        return null;
 
                                //
                                // Case 1: Array
                                //
-                               if (initializer.Type.IsArray) {
-                                       TypeSpec array_type = TypeManager.GetElementType (initializer.Type);
+                               var ac = res.Type as ArrayContainer;
+                               if (ac != null) {
+                                       TypeSpec array_type = ac.Element;
 
                                        //
                                        // Provided that array_type is unmanaged,
@@ -6353,11 +6364,20 @@ 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.
                                        //
-                                       ArrayPtr array_ptr = new ArrayPtr (initializer, array_type, loc);
+                                       ArrayPtr array_ptr = new ArrayPtr (res, array_type, loc);
 
                                        Expression converted = Convert.ImplicitConversionRequired (bc, array_ptr.Resolve (bc), li.Type, loc);
                                        if (converted == null)
@@ -6367,8 +6387,8 @@ 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, initializer, new NullLiteral (loc)),
-                                               new Binary (Binary.Operator.Equality, new MemberAccess (initializer, "Length"), new IntConstant (bc.BuiltinTypes, 0, 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);
 
@@ -6380,33 +6400,39 @@ namespace Mono.CSharp {
                                //
                                // Case 2: string
                                //
-                               if (initializer.Type.BuiltinType == BuiltinTypeSpec.Type.String) {
-                                       return new StringEmitter (initializer, li).Resolve (bc);
+                               if (res.Type.BuiltinType == BuiltinTypeSpec.Type.String) {
+                                       return new StringEmitter (res, li).Resolve (bc);
                                }
 
                                // Case 3: fixed buffer
-                               if (initializer is FixedBufferPtr) {
-                                       return new ExpressionEmitter (initializer, li);
+                               if (res is FixedBufferPtr) {
+                                       return new ExpressionEmitter (res, li);
                                }
 
+                               bool already_fixed = true;
+
                                //
                                // Case 4: & object.
                                //
-                               bool already_fixed = true;
-                               Unary u = initializer as Unary;
-                               if (u != null && u.Oper == Unary.Operator.AddressOf) {
-                                       IVariableReference vr = u.Expr as IVariableReference;
-                                       if (vr == null || !vr.IsFixed) {
-                                               already_fixed = false;
+                               Unary u = res as Unary;
+                               if (u != null) {
+                                       if (u.Oper == Unary.Operator.AddressOf) {
+                                               IVariableReference vr = u.Expr as IVariableReference;
+                                               if (vr == null || !vr.IsFixed) {
+                                                       already_fixed = false;
+                                               }
                                        }
+                               } else if (initializer is Cast) {
+                                       bc.Report.Error (254, initializer.Location, "The right hand side of a fixed statement assignment may not be a cast expression");
+                                       return null;
                                }
 
                                if (already_fixed) {
                                        bc.Report.Error (213, loc, "You cannot use the fixed statement to take the address of an already fixed expression");
                                }
 
-                               initializer = Convert.ImplicitConversionRequired (bc, initializer, li.Type, loc);
-                               return new ExpressionEmitter (initializer, li);
+                               res = Convert.ImplicitConversionRequired (bc, res, li.Type, loc);
+                               return new ExpressionEmitter (res, li);
                        }
                }
 
@@ -6844,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) {
@@ -6852,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)
@@ -8174,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 ();
+               }
+       }
 }