X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fstatement.cs;h=369343a5df7703515bec4e4f8963e4f71772467e;hb=135dbb9c6d6add208ac0d0f763319fa37ecd6c11;hp=dd7f737139ea372f64af929377608936fd582120;hpb=e1b061052dccfc4c1340942f5b64a6216b9beb38;p=mono.git diff --git a/mcs/mcs/statement.cs b/mcs/mcs/statement.cs index dd7f737139e..369343a5df7 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); @@ -578,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); // @@ -1271,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; } } @@ -2184,7 +2207,7 @@ namespace Mono.CSharp { } if (type == null) { - type = type_expr.ResolveAsType (bc); + type = ResolveTypeExpression (bc); if (type == null) return false; @@ -2207,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 } @@ -2236,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); @@ -2363,6 +2410,7 @@ namespace Mono.CSharp { UsingVariable = 1 << 7, IsLocked = 1 << 8, SymbolFileHidden = 1 << 9, + ByRef = 1 << 10, ReadonlyMask = ForeachVariable | FixedVariable | UsingVariable } @@ -2447,6 +2495,8 @@ namespace Mono.CSharp { } } + public bool IsByRef => (flags & Flags.ByRef) != 0; + public bool IsCompilerGenerated { get { return (flags & Flags.CompilerGenerated) != 0; @@ -2549,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); } @@ -2601,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) @@ -2820,9 +2878,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) @@ -4199,7 +4257,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 ();