**** Merged from MCS ****
authorMartin Baulig <martin@novell.com>
Mon, 12 Jul 2004 17:22:32 +0000 (17:22 -0000)
committerMartin Baulig <martin@novell.com>
Mon, 12 Jul 2004 17:22:32 +0000 (17:22 -0000)
svn path=/trunk/mcs/; revision=31045

mcs/gmcs/ChangeLog
mcs/gmcs/assign.cs
mcs/gmcs/ecore.cs

index a0c368b32fbea9fb0d1c9a42217f833182540a76..c84e6706ae69337984483009072384801f808c9f 100755 (executable)
@@ -1,3 +1,12 @@
+2004-07-09  Miguel de Icaza  <miguel@ximian.com>
+
+       * assign.cs (LocalTemporary): Add new argument: is_address,If
+       `is_address' is true, then the value that we store is the address
+       to the real value, and not the value itself.
+       
+       * ecore.cs (PropertyExpr): use the new local temporary
+       stuff to allow us to handle X.Y += z (where X is a struct)
+
 2004-07-08  Martin Baulig  <martin@ximian.com>
 
        * statement.cs (Lock.Resolve): Set ec.NeedReturnLabel() if we do
index 3f1827e5cfa224567e6d603db54f77fcd5552e22..48c55c219c842f81b99e7aacecea4a59f906b06c 100755 (executable)
@@ -55,24 +55,34 @@ namespace Mono.CSharp {
        ///   The local temporary is used to alter the normal flow of code generation
        ///   basically it creates a local variable, and its emit instruction generates
        ///   code to access this value, return its address or save its value.
+       ///
+       ///   If `is_address' is true, then the value that we store is the address to the
+       ///   real value, and not the value itself. 
+       ///
+       ///   This is needed for a value type, because otherwise you just end up making a
+       ///   copy of the value on the stack and modifying it. You really need a pointer
+       ///   to the origional value so that you can modify it in that location. This
+       ///   Does not happen with a class because a class is a pointer -- so you always
+       ///   get the indirection.
+       ///
+       ///   The `is_address' stuff is really just a hack. We need to come up with a better
+       ///   way to handle it.
        /// </remarks>
        public class LocalTemporary : Expression, IMemoryLocation {
                LocalBuilder builder;
+               bool is_address;
                
-               public LocalTemporary (EmitContext ec, Type t)
+               public LocalTemporary (EmitContext ec, Type t) : this (ec, t, false) {}
+                       
+               public LocalTemporary (EmitContext ec, Type t, bool is_address) 
                {
                        type = t;
                        eclass = ExprClass.Value;
                        loc = Location.Null;
-                       builder = ec.GetTemporaryLocal (t);
+                       builder = ec.GetTemporaryLocal (is_address ? TypeManager.GetReferenceType (t): t);
+                       this.is_address = is_address;
                }
 
-               public void Release (EmitContext ec)
-               {
-                       ec.FreeTemporaryLocal (builder, type);
-                       builder = null;
-               }
-               
                public LocalTemporary (LocalBuilder b, Type t)
                {
                        type = t;
@@ -80,6 +90,12 @@ namespace Mono.CSharp {
                        loc = Location.Null;
                        builder = b;
                }
+
+               public void Release (EmitContext ec)
+               {
+                       ec.FreeTemporaryLocal (builder, type);
+                       builder = null;
+               }
                
                public override Expression DoResolve (EmitContext ec)
                {
@@ -88,17 +104,39 @@ namespace Mono.CSharp {
 
                public override void Emit (EmitContext ec)
                {
-                       ec.ig.Emit (OpCodes.Ldloc, builder); 
+                       ILGenerator ig = ec.ig;
+                       
+                       ig.Emit (OpCodes.Ldloc, builder);
+                       // we need to copy from the pointer
+                       if (is_address)
+                               LoadFromPtr (ig, type);
                }
 
+               // NB: if you have `is_address' on the stack there must
+               // be a managed pointer. Otherwise, it is the type from
+               // the ctor.
                public void Store (EmitContext ec)
                {
-                       ec.ig.Emit (OpCodes.Stloc, builder);
+                       ILGenerator ig = ec.ig;
+                       ig.Emit (OpCodes.Stloc, builder);
                }
 
                public void AddressOf (EmitContext ec, AddressOp mode)
                {
-                       ec.ig.Emit (OpCodes.Ldloca, builder);
+                       // if is_address, than this is just the address anyways,
+                       // so we just return this.
+                       ILGenerator ig = ec.ig;
+                               
+                       if (is_address)
+                               ig.Emit (OpCodes.Ldloc, builder);
+                       else
+                               ig.Emit (OpCodes.Ldloca, builder);
+               }
+
+               public bool PointsToAddress {
+                       get {
+                               return is_address;
+                       }
                }
        }
 
@@ -386,7 +424,7 @@ namespace Mono.CSharp {
                        // just use `dup' to propagate the result
                        // 
                        IAssignMethod am = (IAssignMethod) target;
-                       
+
                        if (this is CompoundAssign)
                                am.CacheTemporaries (ec);
 
index 02265965487956672f017ee00a61261a8b317aef..37e0ce1853c1c773584fe20047af2ab366a37dac 100755 (executable)
@@ -3495,21 +3495,40 @@ namespace Mono.CSharp {
                                              PropertyInfo.DeclaringType + "." +PropertyInfo.Name);
                                return null;
                        }
+
+                       //
+                       // Check that we are not making changes to a temporary memory location
+                       //
+                       if (instance_expr != null && instance_expr.Type.IsValueType && !(instance_expr is IMemoryLocation)) {
+                               // FIXME: Provide better error reporting.
+                               Error (1612, "Cannot modify expression because it is not a variable.");
+                               return null;
+                       }
+
                        return this;
                }
 
                public override void CacheTemporaries (EmitContext ec)
                {
-                       if (!is_static)
-                               temporary = new LocalTemporary (ec, instance_expr.Type);
+                       if (!is_static){
+                               // we need to do indirection on the pointer
+                               bool need_address = instance_expr.Type.IsValueType;
+                               temporary = new LocalTemporary (ec, instance_expr.Type, need_address);
+                       }
                }
 
                Expression EmitInstance (EmitContext ec)
                {
                        if (temporary != null){
                                if (!have_temporary){
-                                       instance_expr.Emit (ec);
+                                       if (temporary.PointsToAddress){
+                                               // must store the managed pointer
+                                               IMemoryLocation loc = instance_expr as IMemoryLocation;
+                                               loc.AddressOf (ec, AddressOp.LoadStore);
+                                       } else 
+                                               instance_expr.Emit (ec);
                                        temporary.Store (ec);
+                                               
                                        have_temporary = true;
                                }
                                return temporary;