2002-02-21 Miguel de Icaza <miguel@ximian.com>
authorMiguel de Icaza <miguel@gnome.org>
Thu, 21 Feb 2002 02:35:01 +0000 (02:35 -0000)
committerMiguel de Icaza <miguel@gnome.org>
Thu, 21 Feb 2002 02:35:01 +0000 (02:35 -0000)
* expression.cs (MakeByteBlob): Removed the hacks we had in place
before we supported unsafe code.

* makefile: add --unsafe to the self compilation of mcs.

2002-02-20  Miguel de Icaza  <miguel@ximian.com>

* expression.cs (PointerArithmetic): New class that is used to
perform pointer arithmetic.
(Binary.Resolve): Handle pointer arithmetic
Handle pointer comparission.
(ArrayPtr): Utility expression class that is used to take the
address of an array.

(ElementAccess): Implement array access for pointers

* statement.cs (Fixed): Implement fixed statement for arrays, we
are missing one more case before we are done.

svn path=/trunk/mcs/; revision=2553

mcs/errors/cs0196.cs [new file with mode: 0755]
mcs/errors/cs0242.cs [new file with mode: 0755]
mcs/mcs/ChangeLog
mcs/mcs/TODO
mcs/mcs/expression.cs
mcs/mcs/makefile
mcs/mcs/statement.cs
mcs/tests/unsafe-1.cs

diff --git a/mcs/errors/cs0196.cs b/mcs/errors/cs0196.cs
new file mode 100755 (executable)
index 0000000..edf4e6f
--- /dev/null
@@ -0,0 +1,11 @@
+// cs0196.cs: pointers must be indexed by a single value
+// line: 8
+using System;
+unsafe class ZZ {
+       static void Main () {
+               int *p = null;
+
+               if (p [10,4] == 4)
+                       ;
+       }
+}
diff --git a/mcs/errors/cs0242.cs b/mcs/errors/cs0242.cs
new file mode 100755 (executable)
index 0000000..2a927d8
--- /dev/null
@@ -0,0 +1,11 @@
+// cs0242: operation is not defined for void *
+// Line: 8
+using System;
+unsafe class ZZ {
+       static void Main () {
+               void *p = null;
+
+               if (p [10] == 4)
+                       ;
+       }
+}
index 0a7492915c688a5bfeba2190792fa75c72759d6d..037e5c92acd2d0a337a13397c6d56274705a7bb0 100755 (executable)
@@ -1,9 +1,28 @@
+2002-02-21  Miguel de Icaza  <miguel@ximian.com>
+
+       * expression.cs (MakeByteBlob): Removed the hacks we had in place
+       before we supported unsafe code.
+       
+       * makefile: add --unsafe to the self compilation of mcs.
+
 2002-02-20  Miguel de Icaza  <miguel@ximian.com>
 
+       * expression.cs (PointerArithmetic): New class that is used to
+       perform pointer arithmetic.
+       (Binary.Resolve): Handle pointer arithmetic
+       Handle pointer comparission.
+       (ArrayPtr): Utility expression class that is used to take the
+       address of an array.
+
+       (ElementAccess): Implement array access for pointers
+       
+       * statement.cs (Fixed): Implement fixed statement for arrays, we
+       are missing one more case before we are done.
+
        * expression.cs (Indirection): Implement EmitAssign and set the
        ExprClass to Variable.  This allows pointer dereferences to be
        treated as variables, and to have values assigned to them.
-
+       
        * ecore.cs (Expression.StoreFromPtr): New utility function to
        store values dereferencing.
 
index e669c19c25589b95559878fb7b7c909b0ee99db7..a862d41d3bd08fe8b95bf5fb925907fb7a51576d 100644 (file)
@@ -145,14 +145,10 @@ BUGS
 PENDING TASKS
 -------------
 
-* Code compiled with /unsafe needs:
-       .module b.exe
-       // MVID: {E01E6512-AD32-4108-A407-3857203C261C}
-       .custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 ) 
+* Implement (fixed case 3: string)
 
+* Implement stackalloc.
        
-* Pointer Arithmetic
-
 * Revisit
 
        Primary-expression, as it has now been split into 
index a7e49c1819f856202f7063d41ff7526184909ef8..b6cfc834c549e138e4755974fa3681cc33653afd 100755 (executable)
@@ -548,6 +548,9 @@ namespace Mono.CSharp {
 
                public override Expression DoResolve (EmitContext ec)
                {
+                       //
+                       // Born fully resolved
+                       //
                        return this;
                }
        }
@@ -1539,7 +1542,13 @@ namespace Mono.CSharp {
                               TypeManager.CSharpName (right.Type) + "'");
                                                     
                }
-               
+
+               static bool is_32_or_64 (Type t)
+               {
+                       return (t == TypeManager.int32_type || t == TypeManager.uint32_type ||
+                               t == TypeManager.int64_type || t == TypeManager.uint64_type);
+               }
+                                       
                Expression CheckShiftArguments (EmitContext ec)
                {
                        Expression e;
@@ -1684,6 +1693,38 @@ namespace Mono.CSharp {
                                        type = l;
                                        return this;
                                }
+
+                               //
+                               // Pointer arithmetic:
+                               //
+                               // T* operator + (T* x, int y);
+                               // T* operator + (T* x, uint y);
+                               // T* operator + (T* x, long y);
+                               // T* operator + (T* x, ulong y);
+                               //
+                               // T* operator + (int y,   T* x);
+                               // T* operator + (uint y,  T *x);
+                               // T* operator + (long y,  T *x);
+                               // T* operator + (ulong y, T *x);
+                               //
+                               // T* operator - (T* x, int y);
+                               // T* operator - (T* x, uint y);
+                               // T* operator - (T* x, long y);
+                               // T* operator - (T* x, ulong y);
+                               //
+                               // long operator - (T* x, T *y)
+                               //
+                               if (l.IsPointer){
+                                       if (r.IsPointer && oper == Operator.Subtraction){
+                                               if (r == l)
+                                                       return new PointerArithmetic (
+                                                               false, left, right, TypeManager.int64_type);
+                                       } else if (is_32_or_64 (r))
+                                               return new PointerArithmetic (
+                                                       oper == Operator.Addition, left, right, l);
+                               } else if (r.IsPointer && is_32_or_64 (l) && oper == Operator.Addition)
+                                       return new PointerArithmetic (
+                                               true, right, left, r);
                        }
                        
                        //
@@ -1776,6 +1817,18 @@ namespace Mono.CSharp {
                                }
                        }
 
+                       //
+                       // Pointer comparison
+                       //
+                       if (l.IsPointer && r.IsPointer){
+                               if (oper == Operator.Equality || oper == Operator.Inequality ||
+                                   oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
+                                   oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
+                                       type = TypeManager.bool_type;
+                                       return this;
+                               }
+                       }
+                       
                        //
                        // We are dealing with numbers
                        //
@@ -2175,6 +2228,74 @@ namespace Mono.CSharp {
                }
        }
 
+       public class PointerArithmetic : Expression {
+               Expression left, right;
+               bool is_add;
+
+               //
+               // We assume that `l' is always a pointer
+               //
+               public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t)
+               {
+                       type = t;
+                       eclass = ExprClass.Variable;
+                       left = l;
+                       right = r;
+                       is_add = is_addition;
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       //
+                       // We are born fully resolved
+                       //
+                       return this;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       Type op_type = left.Type;
+                       ILGenerator ig = ec.ig;
+                       int size = GetTypeSize (op_type.GetElementType ());
+                       
+                       if (right.Type.IsPointer){
+                               //
+                               // handle (pointer - pointer)
+                               //
+                               left.Emit (ec);
+                               right.Emit (ec);
+                               ig.Emit (OpCodes.Sub);
+
+                               if (size != 1){
+                                       if (size == 0)
+                                               ig.Emit (OpCodes.Sizeof, op_type);
+                                       else 
+                                               IntLiteral.EmitInt (ig, size);
+                                       ig.Emit (OpCodes.Div);
+                               }
+                               ig.Emit (OpCodes.Conv_I8);
+                       } else {
+                               //
+                               // handle + and - on (pointer op int)
+                               //
+                               left.Emit (ec);
+                               ig.Emit (OpCodes.Conv_I);
+                               right.Emit (ec);
+                               if (size != 1){
+                                       if (size == 0)
+                                               ig.Emit (OpCodes.Sizeof, op_type);
+                                       else 
+                                               IntLiteral.EmitInt (ig, size);
+                                       ig.Emit (OpCodes.Mul);
+                               }
+                               if (is_add)
+                                       ig.Emit (OpCodes.Add);
+                               else
+                                       ig.Emit (OpCodes.Sub);
+                       }
+               }
+       }
+       
        /// <summary>
        ///   Implements the ternary conditiona operator (?:)
        /// </summary>
@@ -4119,8 +4240,6 @@ namespace Mono.CSharp {
                                                }
                                        }
                                } else if (underlying_type == TypeManager.float_type) {
-#if __MonoCS__
-#else
                                        unsafe {
                                                if (!(v is Expression)){
                                                        float val = (float) v;
@@ -4131,10 +4250,7 @@ namespace Mono.CSharp {
                                                                data [idx + j] = (byte) ptr [j];
                                                }
                                        }
-#endif
                                } else if (underlying_type == TypeManager.double_type) {
-#if __MonoCS__
-#else
                                        unsafe {
                                                if (!(v is Expression)){
                                                        double val = (double) v;
@@ -4145,7 +4261,6 @@ namespace Mono.CSharp {
                                                                data [idx + j] = (byte) ptr [j];
                                                }
                                        }
-#endif
                                } else if (underlying_type == TypeManager.char_type){
 
                                        if (!(v is Expression)){
@@ -4947,7 +5062,27 @@ namespace Mono.CSharp {
 
                        return true;
                }
-                               
+
+               Expression MakePointerAccess ()
+               {
+                       Type t = Expr.Type;
+
+                       if (t == TypeManager.void_ptr_type){
+                               Report.Error (
+                                       242, loc,
+                                       "The array index operation is not valid for void pointers");
+                               return null;
+                       }
+                       if (Arguments.Count != 1){
+                               Report.Error (
+                                       196, loc,
+                                       "A pointer must be indexed by a single value");
+                               return null;
+                       }
+                       Expression p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t);
+                       return new Indirection (p);
+               }
+               
                public override Expression DoResolve (EmitContext ec)
                {
                        if (!CommonResolve (ec))
@@ -4959,8 +5094,12 @@ namespace Mono.CSharp {
                        //
                        // I am experimenting with this pattern.
                        //
-                       if (Expr.Type.IsSubclassOf (TypeManager.array_type))
+                       Type t = Expr.Type;
+
+                       if (t.IsSubclassOf (TypeManager.array_type))
                                return (new ArrayAccess (this)).Resolve (ec);
+                       else if (t.IsPointer)
+                               return MakePointerAccess ();
                        else
                                return (new IndexerAccess (this)).Resolve (ec);
                }
@@ -4970,8 +5109,11 @@ namespace Mono.CSharp {
                        if (!CommonResolve (ec))
                                return null;
 
-                       if (Expr.Type.IsSubclassOf (TypeManager.array_type))
+                       Type t = Expr.Type;
+                       if (t.IsSubclassOf (TypeManager.array_type))
                                return (new ArrayAccess (this)).ResolveLValue (ec, right_side);
+                       else if (t.IsPointer)
+                               return MakePointerAccess ();
                        else
                                return (new IndexerAccess (this)).ResolveLValue (ec, right_side);
                }
@@ -5005,7 +5147,6 @@ namespace Mono.CSharp {
                        }
 
                        Type t = ea.Expr.Type;
-
                        if (t.GetArrayRank () != ea.Arguments.Count){
                                Report.Error (22, ea.loc,
                                              "Incorrect number of indexes for array " +
@@ -5549,7 +5690,6 @@ namespace Mono.CSharp {
                                ig.Emit (OpCodes.Call, (ConstructorInfo) method);
 
                }
-
        }
 
        // <summary>
@@ -5600,4 +5740,48 @@ namespace Mono.CSharp {
                        throw new Exception ("This should never be called");
                }
        }
+
+       //
+       // This class is used to represent the address of an array, used
+       // only by the Fixed statement, this is like the C "&a [0]" construct.
+       //
+       public class ArrayPtr : Expression {
+               Expression array;
+               
+               public ArrayPtr (Expression array)
+               {
+                       Type array_type = array.Type.GetElementType ();
+
+                       this.array = array;
+                       
+                       string array_ptr_type_name = array_type.FullName + "*";
+                       
+                       type = Type.GetType (array_ptr_type_name);
+                       if (type == null){
+                               ModuleBuilder mb = RootContext.ModuleBuilder;
+                               
+                               type = mb.GetType (array_ptr_type_name);
+                       }
+
+                       eclass = ExprClass.Value;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       ILGenerator ig = ec.ig;
+                       
+                       array.Emit (ec);
+                       IntLiteral.EmitInt (ig, 0);
+                       ig.Emit (OpCodes.Ldelema, array.Type.GetElementType ());
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       //
+                       // We are born fully resolved
+                       //
+                       return this;
+               }
+       }
+       
 }
index b4bd9206d80c1bd544677c79819a6d9e6a285a25..e6988e1932de26d3bd2b56c443fcb0554be3a649 100755 (executable)
@@ -45,10 +45,10 @@ dum: cs-parser.cs
        ./mcs --fatal --target exe -o mcs2.exe $(COMPILER_SOURCES)
 
 mcs2.exe: mcs.exe
-       ./mcs --target exe -o mcs2.exe $(COMPILER_SOURCES)
+       ./mcs --target exe --unsafe -o mcs2.exe $(COMPILER_SOURCES)
 
 mcs3.exe: mcs2.exe
-       ./mcs2 --target exe -o mcs3.exe $(COMPILER_SOURCES)
+       ./mcs2 --target exe --unsafe -o mcs3.exe $(COMPILER_SOURCES)
 
 test: mcs3.exe
        ls -l mcs2.exe mcs3.exe
index 40082bf81022d07a51b9ae2625f9677e2a5817bf..0a48f07abd74cc95638496c3133a1dfdc28184d4 100755 (executable)
@@ -1812,17 +1812,10 @@ namespace Mono.CSharp {
                                        // and T* is implicitly convertible to the
                                        // pointer type given in the fixed statement.
                                        //
-                                       string array_ptr_type_name = array_type.FullName + "*";
-                                       Type array_ptr_type = Type.GetType (array_ptr_type_name);
-                                       if (array_ptr_type == null){
-                                               ModuleBuilder mb = RootContext.ModuleBuilder;
-
-                                               array_ptr_type = mb.GetType (array_ptr_type_name);
-                                       }
-
-#if PENDING
+                                       ArrayPtr array_ptr = new ArrayPtr (e);
+                                       
                                        Expression converted = Expression.ConvertImplicitRequired (
-                                               ec, array_ptr_type, vi.VariableType, loc);
+                                               ec, array_ptr, vi.VariableType, loc);
                                        if (converted == null)
                                                continue;
 
@@ -1830,7 +1823,6 @@ namespace Mono.CSharp {
                                        // Store pointer in pinned location
                                        //
                                        converted.Emit (ec);
-#endif
                                        
                                        ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
 
index c54d8914eb7dd09c7f4ac9e4f065642e4d04cf5f..b49bc0fe2779fbcb91b15265e7025fd3d00abca1 100755 (executable)
@@ -99,6 +99,48 @@ unsafe class X {
                        return 105;
                return 0;
        }
+
+       static int TestPtrArithmetic ()
+       {
+               char [] array = new char [10];
+               char *pb;
+
+               array [5] = 'j';
+               fixed (char *pa = array){
+                       pb = pa + 1;
+
+
+                       //
+                       // This one tests pointer element access
+                       //
+                       if (pa [5] != 'j')
+                               return 199;
+                       
+                       Console.WriteLine ("V: " + (pb - pa));
+                       if ((pb - pa) != 1)
+                               return 200;
+
+                       pb++;
+
+                       if (pb == pa)
+                               return 201;
+                       if (pb < pa)
+                               return 202;
+                       if (pa > pb)
+                               return 203;
+                       if (pa >= pb)
+                               return 204;
+                       if (pb <= pa)
+                               return 205;
+                       pb = pb - 2;
+                       if (pb != pa){
+                               Console.WriteLine ("VV: " + (pb - pa));
+                               return 206;
+                       }
+               }
+
+               return 0;
+       }
        
        static int Main ()
        {
@@ -112,7 +154,9 @@ unsafe class X {
 
                if ((v = TestPtrAssign ()) != 0)
                        return v;
-               
+
+               if ((v = TestPtrArithmetic ()) != 0)
+                       return v;
                Console.WriteLine ("Ok");
                return 0;
        }