var da_false = new DefiniteAssignmentBitSet (fc.DefiniteAssignmentOnFalse);
- fc.DefiniteAssignment = fc.DefiniteAssignmentOnTrue;
+ fc.BranchDefiniteAssignment (fc.DefiniteAssignmentOnTrue);
var labels = fc.CopyLabelStack ();
var res = TrueStatement.FlowAnalysis (fc);
ec.Emit (OpCodes.Br, ec.LoopBegin);
ec.MarkLabel (while_loop);
+ expr.EmitPrepare (ec);
+
Statement.Emit (ec);
ec.MarkLabel (ec.LoopBegin);
{
expr.FlowAnalysisConditional (fc);
- fc.DefiniteAssignment = fc.DefiniteAssignmentOnTrue;
var da_false = new DefiniteAssignmentBitSet (fc.DefiniteAssignmentOnFalse);
+ fc.BranchDefiniteAssignment (fc.DefiniteAssignmentOnTrue);
+
Statement.FlowAnalysis (fc);
//
public class Return : ExitStatement
{
Expression expr;
+ bool expr_returns;
public Return (Expression expr, Location l)
{
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;
}
}
if (expr != null)
expr.FlowAnalysis (fc);
- base.DoFlowAnalysis (fc);
+ if (!expr_returns)
+ base.DoFlowAnalysis (fc);
+
return true;
}
public override Reachability MarkReachable (Reachability rc)
{
base.MarkReachable (rc);
+
+ if (Expr != null) {
+ rc = Expr.MarkReachable (rc);
+ expr_returns = rc.IsUnreachable;
+ }
+
return Reachability.CreateUnreachable ();
}
}
}
+ 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) {
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;
}
}
if (type == null) {
- type = type_expr.ResolveAsType (bc);
+ type = ResolveTypeExpression (bc);
if (type == null)
return false;
}
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
}
return a.ResolveStatement (bc);
}
+ protected virtual TypeSpec ResolveTypeExpression (BlockContext bc)
+ {
+ return type_expr.ResolveAsType (bc);
+ }
+
protected override void DoEmit (EmitContext ec)
{
li.CreateBuilder (ec);
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)
UsingVariable = 1 << 7,
IsLocked = 1 << 8,
SymbolFileHidden = 1 << 9,
+ ByRef = 1 << 10,
ReadonlyMask = ForeachVariable | FixedVariable | UsingVariable
}
}
}
+ 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;
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);
}
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)
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)
}
}
- 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<string, object> ();
ec.Emit (OpCodes.Br, end);
ec.MarkLabel (labels [i + 1]);
+
+ ec.EmitInt (0);
+ ec.Emit (OpCodes.Stloc, state_variable);
+
c = catch_sm [i];
ec.AsyncThrowVariable = c.Variable;
c.Block.Emit (ec);