X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fgmcs%2Fexpression.cs;h=eaccda581af45e785e97cd22a9fee2ed83d97f8a;hb=10ce0a085680204df3dcc9e779f617efb487db58;hp=0e3c197e2865b5876ec4ce4c2e6aa647f2fa27b0;hpb=21574ff66d2f70ee11f07e31b55505980c2f122f;p=mono.git diff --git a/mcs/gmcs/expression.cs b/mcs/gmcs/expression.cs index 0e3c197e286..eaccda581af 100644 --- a/mcs/gmcs/expression.cs +++ b/mcs/gmcs/expression.cs @@ -178,20 +178,10 @@ namespace Mono.CSharp { oper_names [(int) Operator.AddressOf] = "op_AddressOf"; } - public static void Error_OperatorCannotBeApplied (Location loc, string oper, Type t) - { - Error_OperatorCannotBeApplied (loc, oper, TypeManager.CSharpName (t)); - } - - public static void Error_OperatorCannotBeApplied (Location loc, string oper, string type) - { - Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'", - oper, type); - } - void Error23 (Type t) { - Error_OperatorCannotBeApplied (loc, OperName (Oper), t); + Report.Error (23, loc, "Operator `{0}' cannot be applied to operand of type `{1}'", + OperName (Oper), TypeManager.CSharpName (t)); } /// @@ -467,8 +457,7 @@ namespace Mono.CSharp { } ParameterReference pr = Expr as ParameterReference; - if ((pr != null) && (ec.capture_context != null) && - ec.capture_context.IsParameterCaptured (pr.Name)) { + if ((pr != null) && pr.Parameter.IsCaptured) { AnonymousMethod.Error_AddressOfCapturedVar (pr.Name, loc); return null; } @@ -3313,16 +3302,116 @@ namespace Mono.CSharp { } + public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation { + bool prepared; + LocalTemporary temp; + + public abstract Variable Variable { + get; + } + + public abstract bool IsRef { + get; + } + + public override void Emit (EmitContext ec) + { + Emit (ec, false); + } + + // + // This method is used by parameters that are references, that are + // being passed as references: we only want to pass the pointer (that + // is already stored in the parameter, not the address of the pointer, + // and not the value of the variable). + // + public void EmitLoad (EmitContext ec) + { + Report.Debug (64, "VARIABLE EMIT LOAD", this, Variable, type, loc); + if (!prepared) + Variable.EmitInstance (ec); + Variable.Emit (ec); + } + + public void Emit (EmitContext ec, bool leave_copy) + { + Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc); + + EmitLoad (ec); + + if (IsRef) { + if (prepared) + ec.ig.Emit (OpCodes.Dup); + + // + // If we are a reference, we loaded on the stack a pointer + // Now lets load the real value + // + LoadFromPtr (ec.ig, type); + } + + if (leave_copy) { + ec.ig.Emit (OpCodes.Dup); + + if (IsRef || Variable.NeedsTemporary) { + temp = new LocalTemporary (Type); + temp.Store (ec); + } + } + } + + public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, + bool prepare_for_load) + { + Report.Debug (64, "VARIABLE EMIT ASSIGN", this, Variable, type, IsRef, + source, loc); + + ILGenerator ig = ec.ig; + prepared = prepare_for_load; + + Variable.EmitInstance (ec); + if (prepare_for_load && Variable.HasInstance) + ig.Emit (OpCodes.Dup); + else if (IsRef && !prepared) + Variable.Emit (ec); + + source.Emit (ec); + + if (leave_copy) { + ig.Emit (OpCodes.Dup); + if (IsRef || Variable.NeedsTemporary) { + temp = new LocalTemporary (Type); + temp.Store (ec); + } + } + + if (IsRef) + StoreFromPtr (ig, type); + else + Variable.EmitAssign (ec); + + if (temp != null) { + temp.Emit (ec); + temp.Release (ec); + } + } + + public void AddressOf (EmitContext ec, AddressOp mode) + { + Variable.EmitInstance (ec); + Variable.EmitAddressOf (ec); + } + } + /// /// Local variables /// - public class LocalVariableReference : Expression, IAssignMethod, IMemoryLocation, IVariable { + public class LocalVariableReference : VariableReference, IVariable { public readonly string Name; public readonly Block Block; public LocalInfo local_info; bool is_readonly; - bool prepared; - LocalTemporary temp; + Variable variable; public LocalVariableReference (Block block, string name, Location l) { @@ -3348,6 +3437,10 @@ namespace Mono.CSharp { get { return local_info.VariableInfo; } } + public override bool IsRef { + get { return false; } + } + public bool IsReadOnly { get { return is_readonly; } } @@ -3377,20 +3470,19 @@ namespace Mono.CSharp { if (!VerifyAssigned (ec)) return null; - if (ec.CurrentAnonymousMethod != null){ - // - // If we are referencing a variable from the external block - // flag it for capturing - // - if ((local_info.Block.Toplevel != ec.CurrentBlock.Toplevel) || - ec.CurrentAnonymousMethod.IsIterator) - { - if (local_info.AddressTaken){ - AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc); - return null; - } - ec.CaptureVariable (local_info); + // + // If we are referencing a variable from the external block + // flag it for capturing + // + if (ec.MustCaptureVariable (local_info)) { + if (local_info.AddressTaken){ + AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc); + return null; } + + ScopeInfo scope = local_info.Block.CreateScopeInfo (); + variable = scope.AddLocal (local_info); + type = variable.Type; } return this; @@ -3417,8 +3509,7 @@ namespace Mono.CSharp { } else if (right_side == EmptyExpression.LValueMemberOutAccess) { code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'"; } else { - Error_CannotAssign (Name, local_info.GetReadOnlyContext ()); - return null; + code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'"; } Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ()); return null; @@ -3454,92 +3545,8 @@ namespace Mono.CSharp { return Name == lvr.Name && Block == lvr.Block; } - public override void Emit (EmitContext ec) - { - ILGenerator ig = ec.ig; - - if (local_info.FieldBuilder == null){ - // - // A local variable on the local CLR stack - // - ig.Emit (OpCodes.Ldloc, local_info.LocalBuilder); - } else { - // - // A local variable captured by anonymous methods. - // - if (!prepared) - ec.EmitCapturedVariableInstance (local_info); - - ig.Emit (OpCodes.Ldfld, local_info.FieldBuilder); - } - } - - public void Emit (EmitContext ec, bool leave_copy) - { - Emit (ec); - if (leave_copy){ - ec.ig.Emit (OpCodes.Dup); - if (local_info.FieldBuilder != null){ - temp = new LocalTemporary (Type); - temp.Store (ec); - } - } - } - - public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) - { - ILGenerator ig = ec.ig; - prepared = prepare_for_load; - - if (local_info.FieldBuilder == null){ - // - // A local variable on the local CLR stack - // - if (local_info.LocalBuilder == null) - throw new Exception ("This should not happen: both Field and Local are null"); - - source.Emit (ec); - if (leave_copy) - ec.ig.Emit (OpCodes.Dup); - ig.Emit (OpCodes.Stloc, local_info.LocalBuilder); - } else { - // - // A local variable captured by anonymous methods or itereators. - // - ec.EmitCapturedVariableInstance (local_info); - - if (prepare_for_load) - ig.Emit (OpCodes.Dup); - source.Emit (ec); - if (leave_copy){ - ig.Emit (OpCodes.Dup); - temp = new LocalTemporary (Type); - temp.Store (ec); - } - ig.Emit (OpCodes.Stfld, local_info.FieldBuilder); - if (temp != null) { - temp.Emit (ec); - temp.Release (ec); - } - } - } - - public void AddressOf (EmitContext ec, AddressOp mode) - { - ILGenerator ig = ec.ig; - - if (local_info.FieldBuilder == null){ - // - // A local variable on the local CLR stack - // - ig.Emit (OpCodes.Ldloca, local_info.LocalBuilder); - } else { - // - // A local variable captured by anonymous methods or iterators - // - ec.EmitCapturedVariableInstance (local_info); - ig.Emit (OpCodes.Ldflda, local_info.FieldBuilder); - } + public override Variable Variable { + get { return variable != null ? variable : local_info.Variable; } } public override string ToString () @@ -3552,13 +3559,13 @@ namespace Mono.CSharp { /// This represents a reference to a parameter in the intermediate /// representation. /// - public class ParameterReference : Expression, IAssignMethod, IMemoryLocation, IVariable { + public class ParameterReference : VariableReference, IVariable { Parameter par; string name; int idx; Block block; VariableInfo vi; - public bool is_ref, is_out, prepared; + public bool is_ref, is_out; public bool IsOut { get { @@ -3566,7 +3573,7 @@ namespace Mono.CSharp { } } - public bool IsRef { + public override bool IsRef { get { return is_ref; } @@ -3578,7 +3585,13 @@ namespace Mono.CSharp { } } - LocalTemporary temp; + public Parameter Parameter { + get { + return par; + } + } + + Variable variable; public ParameterReference (Parameter par, Block block, int idx, Location loc) { @@ -3594,6 +3607,10 @@ namespace Mono.CSharp { get { return vi; } } + public override Variable Variable { + get { return variable != null ? variable : par.Variable; } + } + public bool VerifyFixed () { // A parameter is fixed if it's a value parameter (i.e., no modifier like out, ref, param). @@ -3647,23 +3664,33 @@ namespace Mono.CSharp { if (is_out) vi = block.ParameterMap [idx]; - if (ec.CurrentAnonymousMethod != null){ - if (is_ref && !block.Toplevel.IsLocalParameter (name)){ - Report.Error (1628, Location, "Cannot use ref or out parameter `{0}' inside an anonymous method block", - par.Name); - return false; - } + AnonymousContainer am = ec.CurrentAnonymousMethod; + if (am == null) + return true; - // - // If we are referencing the parameter from the external block - // flag it for capturing - // - //Console.WriteLine ("Is parameter `{0}' local? {1}", name, block.IsLocalParameter (name)); - if (!block.Toplevel.IsLocalParameter (name)){ - ec.CaptureParameter (name, type, idx); + if (is_ref && !block.Toplevel.IsLocalParameter (name)){ + Report.Error (1628, Location, + "Cannot use ref or out parameter `{0}' inside an " + + "anonymous method block", par.Name); + return false; + } + + if (!am.IsIterator && block.Toplevel.IsLocalParameter (name)) + return true; + + AnonymousMethodHost host = null; + ToplevelBlock toplevel = block.Toplevel; + while (toplevel != null) { + if (toplevel.IsLocalParameter (name)) { + host = toplevel.AnonymousMethodHost; + break; } + + toplevel = toplevel.Container; } + variable = host.AddParameter (par, idx); + type = variable.Type; return true; } @@ -3698,7 +3725,8 @@ namespace Mono.CSharp { if (!DoResolveBase (ec)) return null; - if (is_out && ec.DoFlowAnalysis && (!ec.OmitStructFlowAnalysis || !vi.TypeInfo.IsStruct) && !IsAssigned (ec, loc)) + if (is_out && ec.DoFlowAnalysis && + (!ec.OmitStructFlowAnalysis || !vi.TypeInfo.IsStruct) && !IsAssigned (ec, loc)) return null; return this; @@ -3728,137 +3756,6 @@ namespace Mono.CSharp { ig.Emit (OpCodes.Ldarg, x); } - // - // This method is used by parameters that are references, that are - // being passed as references: we only want to pass the pointer (that - // is already stored in the parameter, not the address of the pointer, - // and not the value of the variable). - // - public void EmitLoad (EmitContext ec) - { - ILGenerator ig = ec.ig; - int arg_idx = idx; - - if (!ec.MethodIsStatic) - arg_idx++; - - EmitLdArg (ig, arg_idx); - - // - // FIXME: Review for anonymous methods - // - } - - public override void Emit (EmitContext ec) - { - Emit (ec, false); - } - - public void Emit (EmitContext ec, bool leave_copy) - { - ILGenerator ig = ec.ig; - int arg_idx = idx; - - if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){ - ec.EmitParameter (name, leave_copy, prepared, ref temp); - return; - } - - if (!ec.MethodIsStatic) - arg_idx++; - - EmitLdArg (ig, arg_idx); - - if (is_ref) { - if (prepared) - ec.ig.Emit (OpCodes.Dup); - - // - // If we are a reference, we loaded on the stack a pointer - // Now lets load the real value - // - LoadFromPtr (ig, type); - } - - if (leave_copy) { - ec.ig.Emit (OpCodes.Dup); - - if (is_ref) { - temp = new LocalTemporary (type); - temp.Store (ec); - } - } - } - - public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) - { - prepared = prepare_for_load; - if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){ - ec.EmitAssignParameter (name, source, leave_copy, prepare_for_load, ref temp); - return; - } - - ILGenerator ig = ec.ig; - int arg_idx = idx; - - - - if (!ec.MethodIsStatic) - arg_idx++; - - if (is_ref && !prepared) - EmitLdArg (ig, arg_idx); - - source.Emit (ec); - - if (leave_copy) - ec.ig.Emit (OpCodes.Dup); - - if (is_ref) { - if (leave_copy) { - temp = new LocalTemporary (type); - temp.Store (ec); - } - - StoreFromPtr (ig, type); - - if (temp != null) { - temp.Emit (ec); - temp.Release (ec); - } - } else { - if (arg_idx <= 255) - ig.Emit (OpCodes.Starg_S, (byte) arg_idx); - else - ig.Emit (OpCodes.Starg, arg_idx); - } - } - - public void AddressOf (EmitContext ec, AddressOp mode) - { - if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){ - ec.EmitAddressOfParameter (name); - return; - } - - int arg_idx = idx; - - if (!ec.MethodIsStatic) - arg_idx++; - - if (is_ref){ - if (arg_idx <= 255) - ec.ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx); - else - ec.ig.Emit (OpCodes.Ldarg, arg_idx); - } else { - if (arg_idx <= 255) - ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx); - else - ec.ig.Emit (OpCodes.Ldarga, arg_idx); - } - } - public override string ToString () { return "ParameterReference[" + name + "]"; @@ -6624,6 +6521,7 @@ namespace Mono.CSharp { { eclass = ExprClass.Variable; type = ec.ContainerType; + variable = new SimpleThis (type); return this; } } @@ -6632,11 +6530,13 @@ namespace Mono.CSharp { /// Represents the `this' construct /// - public class This : Expression, IAssignMethod, IMemoryLocation, IVariable { - + public class This : VariableReference, IVariable + { Block block; VariableInfo variable_info; - + protected Variable variable; + bool is_struct; + public This (Block block, Location loc) { this.loc = loc; @@ -6657,6 +6557,14 @@ namespace Mono.CSharp { return !TypeManager.IsValueType (Type); } + public override bool IsRef { + get { return is_struct; } + } + + public override Variable Variable { + get { return variable; } + } + public bool ResolveBase (EmitContext ec) { eclass = ExprClass.Variable; @@ -6666,16 +6574,38 @@ namespace Mono.CSharp { else type = ec.ContainerType; + is_struct = ec.TypeContainer is Struct; + if (ec.IsStatic) { - Error (26, "Keyword `this' is not valid in a static property, static method, or static field initializer"); + Error (26, "Keyword `this' is not valid in a static property, " + + "static method, or static field initializer"); return false; } - if (block != null && block.Toplevel.ThisVariable != null) - variable_info = block.Toplevel.ThisVariable.VariableInfo; + if (block != null) { + if (block.Toplevel.ThisVariable != null) + variable_info = block.Toplevel.ThisVariable.VariableInfo; - if (ec.CurrentAnonymousMethod != null) - ec.CaptureThis (); + AnonymousContainer am = ec.CurrentAnonymousMethod; + if (is_struct && (am != null) && !am.IsIterator) { + Report.Error (1673, loc, "Anonymous methods inside structs " + + "cannot access instance members of `this'. " + + "Consider copying `this' to a local variable " + + "outside the anonymous method and using the " + + "local instead."); + return false; + } + + AnonymousMethodHost host = block.Toplevel.AnonymousMethodHost; + if ((host != null) && (!is_struct || host.IsIterator)) { + variable = host.CaptureThis (); + type = variable.Type; + is_struct = false; + } + } + + if (variable == null) + variable = new SimpleThis (type); return true; } @@ -6685,8 +6615,10 @@ namespace Mono.CSharp { if (!ResolveBase (ec)) return null; - if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) && !variable_info.IsAssigned (ec)) { - Error (188, "The `this' object cannot be used before all of its fields are assigned to"); + if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) && + !variable_info.IsAssigned (ec)) { + Error (188, "The `this' object cannot be used before all of its " + + "fields are assigned to"); variable_info.SetAssigned (ec); return this; } @@ -6714,49 +6646,6 @@ namespace Mono.CSharp { return this; } - - public void Emit (EmitContext ec, bool leave_copy) - { - Emit (ec); - if (leave_copy) - ec.ig.Emit (OpCodes.Dup); - } - - public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) - { - ILGenerator ig = ec.ig; - - if (ec.TypeContainer is Struct){ - ec.EmitThis (false); - source.Emit (ec); - - LocalTemporary t = null; - if (leave_copy) { - t = new LocalTemporary (type); - ec.ig.Emit (OpCodes.Dup); - t.Store (ec); - } - - ig.Emit (OpCodes.Stobj, type); - - if (leave_copy) { - t.Emit (ec); - t.Release (ec); - } - } else { - throw new Exception ("how did you get here"); - } - } - - public override void Emit (EmitContext ec) - { - ILGenerator ig = ec.ig; - - ec.EmitThis (false); - if (ec.TypeContainer is Struct) - ig.Emit (OpCodes.Ldobj, type); - } - public override int GetHashCode() { return block.GetHashCode (); @@ -6771,18 +6660,46 @@ namespace Mono.CSharp { return block == t.block; } - public void AddressOf (EmitContext ec, AddressOp mode) + protected class SimpleThis : Variable { - ec.EmitThis (true); + Type type; - // FIMXE - // FIGURE OUT WHY LDARG_S does not work - // - // consider: struct X { int val; int P { set { val = value; }}} - // - // Yes, this looks very bad. Look at `NOTAS' for - // an explanation. - // ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0); + public SimpleThis (Type type) + { + this.type = type; + } + + public override Type Type { + get { return type; } + } + + public override bool HasInstance { + get { return false; } + } + + public override bool NeedsTemporary { + get { return false; } + } + + public override void EmitInstance (EmitContext ec) + { + // Do nothing. + } + + public override void Emit (EmitContext ec) + { + ec.ig.Emit (OpCodes.Ldarg_0); + } + + public override void EmitAssign (EmitContext ec) + { + throw new InvalidOperationException (); + } + + public override void EmitAddressOf (EmitContext ec) + { + ec.ig.Emit (OpCodes.Ldarg_0); + } } } @@ -7128,26 +7045,21 @@ namespace Mono.CSharp { TypeArguments args; public MemberAccess (Expression expr, string id) - : this (expr, id, null) + : this (expr, id, expr.Location) { } - public MemberAccess (Expression expr, string identifier, Location loc, TypeArguments args) + public MemberAccess (Expression expr, string identifier, Location loc) { this.expr = expr; Identifier = identifier; this.loc = loc; - this.args = args; } - public MemberAccess (Expression expr, string id, Location loc) - : this (expr, id, loc, null) - { - } - public MemberAccess (Expression expr, string id, TypeArguments args) - : this (expr, id, expr.Location, args) + : this (expr, id) { + this.args = args; } public Expression Expr { @@ -7188,13 +7100,15 @@ namespace Mono.CSharp { } Type expr_type = new_expr.Type; - if (expr_type.IsPointer || expr_type == TypeManager.void_type || new_expr is NullLiteral){ - Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type); + if (expr_type.IsPointer){ + Error (23, "The `.' operator can not be applied to pointer operands (" + + TypeManager.CSharpName (expr_type) + ")"); return null; - } - if (expr_type == TypeManager.anonymous_method_type){ - Unary.Error_OperatorCannotBeApplied (loc, ".", "anonymous method"); + } else if (expr_type == TypeManager.void_type) { + Error (23, "The `.' operator can not be applied to operands of type 'void'"); return null; + } else if (expr_type == TypeManager.anonymous_method_type){ + Error (23, "The `.' operator can not be applied to anonymous methods"); }