X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fstatement.cs;h=ba58d1f1380ebbb95642eab2d2d03541b839967e;hb=0217438747001f40a4a49d6ab3ffb92866bb2fe4;hp=bee698b231ad966ca805fc5e84aeb1d66e2d5d13;hpb=c7ad272b9afa8eeaab686ce3ca50b170f4ac5c84;p=mono.git diff --git a/mcs/mcs/statement.cs b/mcs/mcs/statement.cs index bee698b231a..ba58d1f1380 100644 --- a/mcs/mcs/statement.cs +++ b/mcs/mcs/statement.cs @@ -1222,7 +1222,7 @@ namespace Mono.CSharp { // // The return type is actually Task 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 (); + } + } }