X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fstatement.cs;h=58ba2795e4b956ffd546f6da75ee39b945fe52c4;hb=3e9d7d6e9cf8dc33eb29c497c350a1cd7df3a057;hp=fbb060f52960da9af8218171c9cf6991e8b102cc;hpb=94b8270e9bdbd9280de1ec144af20877d8c8d055;p=mono.git diff --git a/mcs/mcs/statement.cs b/mcs/mcs/statement.cs index fbb060f5296..58ba2795e4b 100644 --- a/mcs/mcs/statement.cs +++ b/mcs/mcs/statement.cs @@ -269,7 +269,7 @@ 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); @@ -558,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); @@ -576,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); // @@ -771,6 +774,8 @@ namespace Mono.CSharp { ec.Emit (OpCodes.Br, test); ec.MarkLabel (loop); + + Condition?.EmitPrepare (ec); Statement.Emit (ec); ec.MarkLabel (ec.LoopBegin); @@ -1114,6 +1119,7 @@ namespace Mono.CSharp { public class Return : ExitStatement { Expression expr; + bool expr_returns; public Return (Expression expr, Location l) { @@ -1268,16 +1274,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; } } @@ -1301,7 +1329,7 @@ namespace Mono.CSharp { // Special case hoisted return value (happens in try/finally scenario) // if (ec.TryFinallyUnwind != null) { - exit_label = TryFinally.EmitRedirectedReturn (ec, async_body); + exit_label = TryFinally.EmitRedirectedReturn (ec, async_body, unwind_protect); } var async_return = (IAssignMethod)storey.HoistedReturnValue; @@ -1311,7 +1339,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); @@ -1339,7 +1367,9 @@ namespace Mono.CSharp { if (expr != null) expr.FlowAnalysis (fc); - base.DoFlowAnalysis (fc); + if (!expr_returns) + base.DoFlowAnalysis (fc); + return true; } @@ -1352,6 +1382,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 (); } @@ -1460,7 +1496,7 @@ namespace Mono.CSharp { 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); @@ -1767,6 +1803,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) { @@ -1790,11 +1839,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; } @@ -1867,7 +1912,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); @@ -1915,7 +1960,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); @@ -2164,7 +2209,7 @@ namespace Mono.CSharp { } if (type == null) { - type = type_expr.ResolveAsType (bc); + type = ResolveTypeExpression (bc); if (type == null) return false; @@ -2187,6 +2232,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 } @@ -2216,6 +2280,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); @@ -2251,11 +2320,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) @@ -2346,6 +2412,7 @@ namespace Mono.CSharp { UsingVariable = 1 << 7, IsLocked = 1 << 8, SymbolFileHidden = 1 << 9, + ByRef = 1 << 10, ReadonlyMask = ForeachVariable | FixedVariable | UsingVariable } @@ -2418,12 +2485,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; @@ -2526,10 +2601,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); } @@ -2578,7 +2658,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) @@ -2797,9 +2880,9 @@ namespace Mono.CSharp { AddLocalName (li.Name, li); } - public void AddLocalName (string name, INamedBlockVariable li) + public virtual void AddLocalName (string name, INamedBlockVariable li, bool canShadowChildrenBlockName = false) { - ParametersBlock.TopBlock.AddLocalName (name, li, false); + ParametersBlock.TopBlock.AddLocalName (name, li, canShadowChildrenBlockName); } public virtual void Error_AlreadyDeclared (string name, INamedBlockVariable variable, string reason) @@ -4176,7 +4259,7 @@ namespace Mono.CSharp { } } - public void AddLocalName (string name, INamedBlockVariable li, bool ignoreChildrenBlocks) + public override void AddLocalName (string name, INamedBlockVariable li, bool ignoreChildrenBlocks) { if (names == null) names = new Dictionary (); @@ -6357,7 +6440,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); @@ -6997,7 +7080,7 @@ namespace Mono.CSharp { { ExplicitBlock fini; List try_exit_dat; - List