X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fstatement.cs;h=0c02bf0562a271da6811188fd102ecf836f0986a;hb=34866ac4c20c781f10c40fe6f6fe0c39733fd946;hp=703e7ba497fef805446a5df389a8fa4f81258816;hpb=df867664eec6ac0aa851004db0a7cb94ba381602;p=mono.git diff --git a/mcs/mcs/statement.cs b/mcs/mcs/statement.cs index 703e7ba497f..0c02bf0562a 100644 --- a/mcs/mcs/statement.cs +++ b/mcs/mcs/statement.cs @@ -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,7 +1327,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; @@ -1301,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); @@ -1329,7 +1365,9 @@ namespace Mono.CSharp { if (expr != null) expr.FlowAnalysis (fc); - base.DoFlowAnalysis (fc); + if (!expr_returns) + base.DoFlowAnalysis (fc); + return true; } @@ -1342,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 (); } @@ -1450,7 +1494,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); @@ -1757,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) { @@ -1780,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; } @@ -1857,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); @@ -1905,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); @@ -2154,7 +2207,7 @@ namespace Mono.CSharp { } if (type == null) { - type = type_expr.ResolveAsType (bc); + type = ResolveTypeExpression (bc); if (type == null) return false; @@ -2177,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 } @@ -2206,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); @@ -2241,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) @@ -2280,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 } @@ -2333,6 +2410,7 @@ namespace Mono.CSharp { UsingVariable = 1 << 7, IsLocked = 1 << 8, SymbolFileHidden = 1 << 9, + ByRef = 1 << 10, ReadonlyMask = ForeachVariable | FixedVariable | UsingVariable } @@ -2405,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; @@ -2438,6 +2524,12 @@ namespace Mono.CSharp { } } + public bool IsUsed { + get { + return (flags & Flags.Used) != 0; + } + } + public bool IsFixed { get { return (flags & Flags.FixedVariable) != 0; @@ -2507,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); } @@ -2527,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); } @@ -2557,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) @@ -2657,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 @@ -3223,9 +3326,10 @@ namespace Mono.CSharp { public override void Emit (EmitContext ec) { - if (Parent != null) { - // TODO: It's needed only when scope has variable (normal or lifted) - ec.BeginScope (GetDebugSymbolScopeIndex ()); + // TODO: It's needed only when scope has variable (normal or lifted) + var scopeIndex = GetDebugSymbolScopeIndex (); + if (scopeIndex > 0) { + ec.BeginScope (scopeIndex); } EmitScopeInitialization (ec); @@ -3236,7 +3340,7 @@ namespace Mono.CSharp { DoEmit (ec); - if (Parent != null) + if (scopeIndex > 0) ec.EndScope (); if (ec.EmitAccurateDebugInfo && HasReachableClosingBrace && !(this is ParametersBlock) && @@ -3257,6 +3361,7 @@ namespace Mono.CSharp { // storey.CreateContainer (); storey.DefineContainer (); + storey.ExpandBaseInterfaces (); if (Original.Explicit.HasCapturedThis && Original.ParametersBlock.TopBlock.ThisReferencesFromChildrenBlock != null) { @@ -3281,7 +3386,7 @@ namespace Mono.CSharp { break; } } - + // // We are the first storey on path and 'this' has to be hoisted // @@ -3349,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) { @@ -3428,7 +3533,12 @@ namespace Mono.CSharp { storey.Parent.PartialContainer.AddCompilerGeneratedClass (storey); } - public int GetDebugSymbolScopeIndex () + public void DisableDebugScopeIndex () + { + debug_scope_index = -1; + } + + public virtual int GetDebugSymbolScopeIndex () { if (debug_scope_index == 0) debug_scope_index = ++ParametersBlock.debug_scope_index; @@ -3666,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; @@ -3827,6 +3946,11 @@ namespace Mono.CSharp { return res; } + public override int GetDebugSymbolScopeIndex () + { + return 0; + } + public LabeledStatement GetLabel (string name, Block block) { // @@ -6002,7 +6126,7 @@ namespace Mono.CSharp { ec.EmitInt (first_resume_pc); ec.Emit (OpCodes.Sub); - var labels = new Label[resume_points.Count - System.Math.Max (first_catch_resume_pc, 0)]; + 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); @@ -6314,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); @@ -6954,7 +7078,7 @@ namespace Mono.CSharp { { ExplicitBlock fini; List try_exit_dat; - List