Wooohoo! Unsafe code, here I come!
authorMiguel de Icaza <miguel@gnome.org>
Fri, 25 Jan 2002 21:48:12 +0000 (21:48 -0000)
committerMiguel de Icaza <miguel@gnome.org>
Fri, 25 Jan 2002 21:48:12 +0000 (21:48 -0000)
A couple of things are missing, but I will get to that tomorrow.

2002-01-25  Miguel de Icaza  <miguel@ximian.com>

* expression.cs (UnaryMutator.IsIncrementableNumber): Allow also
pointer types to be incretemented.

(SizeOf): Implement.

* cs-parser.jay (pointer_member_access): Implement
expr->IDENTIFIER production.

* expression.cs (IndexerAccess.DoResolve, ArrayAccess.DoResolve,
MemberAccess.DoResolve, Invocation.DoResolve): Check for pointers
on safe contexts.

(Unary): Implement indirection.

* ecore.cs (Expression.UnsafeError): Reports error 214 (pointer
use in non-unsafe context).

(SimpleName.DoResolve): Check for pointers in field access on safe
contexts.

(Expression.LoadFromPtr): Factor the load-indirect code in this
function.  This was duplicated in UnboxCast and ParameterReference

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

mcs/mcs/ChangeLog
mcs/mcs/TODO
mcs/mcs/cs-parser.jay
mcs/mcs/cs-tokenizer.cs
mcs/mcs/decl.cs
mcs/mcs/ecore.cs
mcs/mcs/expression.cs
mcs/tests/makefile
mcs/tools/makefile

index 4c8f96f91228054e27ffae5754247fb1968e35a2..3d6e1873a3b2f67af30cfd9be7832981c504481b 100755 (executable)
@@ -1,3 +1,28 @@
+2002-01-25  Miguel de Icaza  <miguel@ximian.com>
+
+       * expression.cs (UnaryMutator.IsIncrementableNumber): Allow also
+       pointer types to be incretemented.
+
+       (SizeOf): Implement.
+
+       * cs-parser.jay (pointer_member_access): Implement
+       expr->IDENTIFIER production.
+
+       * expression.cs (IndexerAccess.DoResolve, ArrayAccess.DoResolve,
+       MemberAccess.DoResolve, Invocation.DoResolve): Check for pointers
+       on safe contexts.
+
+       (Unary): Implement indirection.
+
+       * ecore.cs (Expression.UnsafeError): Reports error 214 (pointer
+       use in non-unsafe context).
+
+       (SimpleName.DoResolve): Check for pointers in field access on safe
+       contexts. 
+
+       (Expression.LoadFromPtr): Factor the load-indirect code in this
+       function.  This was duplicated in UnboxCast and ParameterReference
+
 2002-01-24  Miguel de Icaza  <miguel@ximian.com>
 
        * expression.cs (ComposedCast): report an error if a pointer cast
index 1826597ab61c57c02d58871c77c03dc480b11307..d324eebb39f66caf4240b4e455c9e53b8d3614de 100644 (file)
@@ -27,6 +27,14 @@ AddressOf
        to track usage errors in variables (since AddressOf does not
        really know what is it being used for, it could be either)
 
+Unsafe code:
+       Pointer arithmetic operators (++ and -- are done)
+       Test for ++ and -- for non-builtin-types
+       sizeof
+       fixed
+
+readonly variables and ref/out
+       
 BUGS
 ----
 
@@ -135,10 +143,10 @@ BUGS
 PENDING TASKS
 -------------
 
-* Unsafe contexts:
-       Done: class, struct, interface
-       Everywhere where we lookup a type, we should test for unsafe pointers.
-       
+* Revisit
+
+       Primary-expression, as it has now been split into 
+       non-array-creation-expression and array-creation-expression.
                
 * Static flow analysis
 
index 1ee28d2265516f92108e7a83c0ccdadcdf83470f..67d928a6634838eb6ea52379fa85f35ce4ccf58a 100755 (executable)
@@ -1822,6 +1822,9 @@ primary_expression
        | sizeof_expression
        | checked_expression
        | unchecked_expression
+       | pointer_member_access
+       // TODO: pointer_element_access
+       // TODO: sizeof-expression
        ;
 
 literal
@@ -2141,7 +2144,7 @@ typeof_expression
 
 sizeof_expression
        : SIZEOF OPEN_PARENS type CLOSE_PARENS { 
-               $$ = new SizeOf ((string) $3);
+               $$ = new SizeOf ((string) $3, lexer.Location);
 
                note ("Verify type is unmanaged"); 
                note ("if (5.8) builtin, yield constant expression");
@@ -2162,6 +2165,15 @@ unchecked_expression
          }
        ;
 
+pointer_member_access 
+       : primary_expression OP_PTR IDENTIFIER
+         {
+               Expression deref;
+
+               deref = new Unary (Unary.Operator.Indirection, (Expression) $1, lexer.Location);
+               $$ = new MemberAccess (deref, (string) $3, lexer.Location);
+         }
+
 unary_expression
        : primary_expression
        | BANG prefixed_unary_expression
@@ -2637,6 +2649,7 @@ embedded_statement
        | lock_statement
        | using_statement
        | unsafe_statement
+       | fixed_statement
        ;
 
 empty_statement
@@ -3271,7 +3284,30 @@ unsafe_statement
        } block {
                $$ = new Unsafe ((Block) $3);
        }
+       ;
 
+fixed_statement
+       : FIXED OPEN_PARENS 
+         // FIXME: pointer_type fixed_pointer_declarators 
+         CLOSE_PARENS embedded_statement
+         {
+               // $$ = new Fixed ((string) $3, $4, (Statement) $6, lexer.Location);
+         }
+       ;
+
+fixed_pointer_declarators
+       : fixed_pointer_declarator
+       | fixed_pointer_declarators COMMA fixed_pointer_declarator
+       ;
+
+fixed_pointer_declarator
+       : IDENTIFIER EQUALS fixed_pointer_initializer
+       ;
+
+fixed_pointer_initializer
+       : BITWISE_AND variable_reference
+       | expression
+       ;
 
 lock_statement
        : LOCK OPEN_PARENS expression CLOSE_PARENS 
index 6df480d56b2cd37ef9e4ce820a4ac85020af8ffc..49d2edbda502eb3a5d96d3ad63de5b383bbdb3c7 100755 (executable)
@@ -329,7 +329,7 @@ namespace Mono.CSharp
                                else if (d == '=')\r
                                        t = Token.OP_SUB_ASSIGN;\r
                                else if (d == '>')\r
-                                       return Token.OP_PTR;\r
+                                       t = Token.OP_PTR;\r
                                else\r
                                        return Token.MINUS;\r
                                doread = true;\r
index aaaa602b0cee2c43de08df0b206be909719f3d7d..813cc295c5666a6b93f5ca4d0837f1c95fd5fce5 100755 (executable)
@@ -109,7 +109,7 @@ namespace Mono.CSharp {
                        if (parent.UnsafeContext)
                                return true;
 
-                       Report.Error (214, Location, "Pointers can only be used in an unsafe context");
+                       Expression.UnsafeError (Location);
                        return false;
                }
        }
index 99df392a1e6c14b6255cbc677d5f80407449bf68..ac75b8d36327ac3a3ecea713a53c07f106722aa0 100755 (executable)
@@ -1249,6 +1249,15 @@ namespace Mono.CSharp {
                                if (expr_type.IsPointer){
                                        if (target_type == TypeManager.void_ptr_type)
                                                return new EmptyCast (expr, target_type);
+
+                                       //
+                                       // yep, comparing pointer types cant be done with
+                                       // t1 == t2, we have to compare their element types.
+                                       //
+                                       if (target_type.IsPointer){
+                                               if (target_type.GetElementType()==expr_type.GetElementType())
+                                                       return expr;
+                                       }
                                }
                                
                                if (target_type.IsPointer){
@@ -1907,6 +1916,11 @@ namespace Mono.CSharp {
                        Report.Error (31, l, "Constant value `" + val + "' cannot be converted to " +
                                      TypeManager.CSharpName (t));
                }
+
+               public static void UnsafeError (Location loc)
+               {
+                       Report.Error (214, loc, "Pointers may only be used in an unsafe context");
+               }
                
                /// <summary>
                ///   Converts the IntConstant, UIntConstant, LongConstant or
@@ -2175,8 +2189,80 @@ namespace Mono.CSharp {
                        }
                        error31 (loc, s, target_type);
                        return null;
-               }               
-                       
+               }
+
+               //
+               // Load the object from the pointer.  The `IsReference' is used
+               // to control whether we should use Ldind_Ref or LdObj if the
+               // value is not a `core' type.
+               //
+               // Maybe we should try to extract this infromation form the type?
+               // TODO: Maybe this is a bug.  The reason we have this flag is because
+               // I had almost identical code in ParameterReference (for handling
+               // references) and in UnboxCast.
+               //
+               public static void LoadFromPtr (ILGenerator ig, Type t, bool IsReference)
+               {
+                       if (t == TypeManager.int32_type)
+                               ig.Emit (OpCodes.Ldind_I4);
+                       else if (t == TypeManager.uint32_type)
+                               ig.Emit (OpCodes.Ldind_U4);
+                       else if (t == TypeManager.short_type)
+                               ig.Emit (OpCodes.Ldind_I2);
+                       else if (t == TypeManager.ushort_type)
+                               ig.Emit (OpCodes.Ldind_U2);
+                       else if (t == TypeManager.char_type)
+                               ig.Emit (OpCodes.Ldind_U2);
+                       else if (t == TypeManager.byte_type)
+                               ig.Emit (OpCodes.Ldind_U1);
+                       else if (t == TypeManager.sbyte_type)
+                               ig.Emit (OpCodes.Ldind_I1);
+                       else if (t == TypeManager.uint64_type)
+                               ig.Emit (OpCodes.Ldind_I8);
+                       else if (t == TypeManager.int64_type)
+                               ig.Emit (OpCodes.Ldind_I8);
+                       else if (t == TypeManager.float_type)
+                               ig.Emit (OpCodes.Ldind_R4);
+                       else if (t == TypeManager.double_type)
+                               ig.Emit (OpCodes.Ldind_R8);
+                       else if (t == TypeManager.bool_type)
+                               ig.Emit (OpCodes.Ldind_I1);
+                       else if (t == TypeManager.intptr_type)
+                               ig.Emit (OpCodes.Ldind_I);
+                       else if (TypeManager.IsEnumType (t)){
+                               LoadFromPtr (ig, TypeManager.EnumToUnderlying (t), IsReference);
+                       } else {
+                               if (IsReference)
+                                       ig.Emit (OpCodes.Ldind_Ref);
+                               else 
+                                       ig.Emit (OpCodes.Ldobj, t);
+                       }
+               }
+
+               //
+               // Returns the size of type `t' if known, otherwise, 0
+               //
+               public static int GetTypeSize (Type t)
+               {
+                       if (t == TypeManager.int32_type ||
+                           t == TypeManager.uint32_type ||
+                           t == TypeManager.float_type)
+                               return 4;
+                       else if (t == TypeManager.int64_type ||
+                                t == TypeManager.uint64_type ||
+                                t == TypeManager.double_type)
+                               return 8;
+                       else if (t == TypeManager.byte_type ||
+                                t == TypeManager.sbyte_type ||
+                                t == TypeManager.bool_type)    
+                               return 1;
+                       else if (t == TypeManager.short_type ||
+                                t == TypeManager.char_type ||
+                                t == TypeManager.ushort_type)
+                               return 2;
+                       else
+                               return 0;
+               }
        }
 
        /// <summary>
@@ -2378,42 +2464,7 @@ namespace Mono.CSharp {
                        base.Emit (ec);
                        ig.Emit (OpCodes.Unbox, t);
 
-                       //
-                       // Load the object from the pointer
-                       //
-               basic_type:
-                       
-                       if (t == TypeManager.int32_type)
-                               ig.Emit (OpCodes.Ldind_I4);
-                       else if (t == TypeManager.uint32_type)
-                               ig.Emit (OpCodes.Ldind_U4);
-                       else if (t == TypeManager.short_type)
-                               ig.Emit (OpCodes.Ldind_I2);
-                       else if (t == TypeManager.ushort_type)
-                               ig.Emit (OpCodes.Ldind_U2);
-                       else if (t == TypeManager.char_type)
-                               ig.Emit (OpCodes.Ldind_U2);
-                       else if (t == TypeManager.byte_type)
-                               ig.Emit (OpCodes.Ldind_U1);
-                       else if (t == TypeManager.sbyte_type)
-                               ig.Emit (OpCodes.Ldind_I1);
-                       else if (t == TypeManager.uint64_type)
-                               ig.Emit (OpCodes.Ldind_I8);
-                       else if (t == TypeManager.int64_type)
-                               ig.Emit (OpCodes.Ldind_I8);
-                       else if (t == TypeManager.float_type)
-                               ig.Emit (OpCodes.Ldind_R4);
-                       else if (t == TypeManager.double_type)
-                               ig.Emit (OpCodes.Ldind_R8);
-                       else if (t == TypeManager.bool_type)
-                               ig.Emit (OpCodes.Ldind_I1);
-                       else if (t == TypeManager.intptr_type)
-                               ig.Emit (OpCodes.Ldind_I);
-                       else if (TypeManager.IsEnumType (t)){
-                               t = TypeManager.EnumToUnderlying (t);
-                               goto basic_type;
-                       } else
-                               ig.Emit (OpCodes.Ldobj, t);
+                       LoadFromPtr (ig, t, false);
                }
        }
        
@@ -2859,6 +2910,10 @@ namespace Mono.CSharp {
                                FieldExpr fe = (FieldExpr) e;
                                FieldInfo fi = fe.FieldInfo;
 
+                               if (fi.FieldType.IsPointer && !ec.InUnsafe){
+                                       UnsafeError (Location);
+                               }
+                               
                                if (ec.IsStatic){
                                        if (!allow_static && !fi.IsStatic){
                                                Error120 (Location, Name);
index e5daf83afbec74cd92c2512b81f7d6c8223eaa05..c491bc4d9cd5ed6da1bb5e061f9e8cb6c09ced06 100755 (executable)
@@ -402,12 +402,33 @@ namespace Mono.CSharp {
                                }
 
                                if (!ec.InUnsafe) {
-                                       Error (214, loc, "Pointers may only be used in an unsafe context");
+                                       UnsafeError (loc); 
                                        return null;
                                }
 
-                               type = Type.GetType (expr.Type.ToString () + "*");
+                               string ptr_type_name = expr.Type.FullName + "*";
+                               type = Type.GetType (ptr_type_name);
+                               if (type == null){
+                                       type = RootContext.ModuleBuilder.GetType (ptr_type_name);
+                               }
+                               
+                               return this;
+                       }
 
+                       if (oper == Operator.Indirection){
+                               if (!ec.InUnsafe){
+                                       UnsafeError (loc);
+                                       return null;
+                               }
+
+                               if (!expr_type.IsPointer){
+                                       Report.Error (
+                                               193, loc,
+                                               "The * or -> operator can only be applied to pointers");
+                                       return null;
+                               }
+                               
+                               type = expr_type.GetElementType ();
                                return this;
                        }
                        
@@ -457,7 +478,9 @@ namespace Mono.CSharp {
                                break;
                                
                        case Operator.Indirection:
-                               throw new Exception ("Not implemented yet");
+                               expr.Emit (ec);
+                               LoadFromPtr (ig, Type, false);
+                               break;
                                
                        default:
                                throw new Exception ("This should not happen: Operator = "
@@ -550,7 +573,8 @@ namespace Mono.CSharp {
                                (t == TypeManager.char_type) ||
                                (t.IsSubclassOf (TypeManager.enum_type)) ||
                                (t == TypeManager.float_type) ||
-                               (t == TypeManager.double_type);
+                               (t == TypeManager.double_type) ||
+                               (t.IsPointer && t != TypeManager.void_ptr_type);
                }
 
                Expression ResolveOperator (EmitContext ec)
@@ -629,8 +653,13 @@ namespace Mono.CSharp {
                        eclass = ExprClass.Value;
                        return ResolveOperator (ec);
                }
-               
 
+               static int PtrTypeSize (Type t)
+               {
+                       return GetTypeSize (t.GetElementType ());
+               }
+               
+               
                //
                // FIXME: We need some way of avoiding the use of temp_storage
                // for some types of storage (parameters, local variables,
@@ -658,7 +687,14 @@ namespace Mono.CSharp {
                                                ig.Emit (OpCodes.Ldc_R8, 1.0);
                                        else if (expr_type == TypeManager.float_type)
                                                ig.Emit (OpCodes.Ldc_R4, 1.0F);
-                                       else
+                                       else if (expr_type.IsPointer){
+                                               int n = PtrTypeSize (expr_type);
+
+                                               if (n == 0)
+                                                       ig.Emit (OpCodes.Sizeof, expr_type);
+                                               else
+                                                       IntConstant.EmitInt (ig, n);
+                                       } else 
                                                ig.Emit (OpCodes.Ldc_I4_1);
                                
                                        if (mode == Mode.PreDecrement)
@@ -692,7 +728,14 @@ namespace Mono.CSharp {
                                                ig.Emit (OpCodes.Ldc_R8, 1.0);
                                        else if (expr_type == TypeManager.float_type)
                                                ig.Emit (OpCodes.Ldc_R4, 1.0F);
-                                       else
+                                       else if (expr_type.IsPointer){
+                                               int n = PtrTypeSize (expr_type);
+
+                                               if (n == 0)
+                                                       ig.Emit (OpCodes.Sizeof, expr_type);
+                                               else
+                                                       IntConstant.EmitInt (ig, n);
+                                       } else
                                                ig.Emit (OpCodes.Ldc_I4_1);
                                
                                        if (mode == Mode.PostDecrement)
@@ -2416,31 +2459,7 @@ namespace Mono.CSharp {
                        // If we are a reference, we loaded on the stack a pointer
                        // Now lets load the real value
                        //
-
-                       if (type == TypeManager.int32_type)
-                               ig.Emit (OpCodes.Ldind_I4);
-                       else if (type == TypeManager.uint32_type)
-                               ig.Emit (OpCodes.Ldind_U4);
-                       else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
-                               ig.Emit (OpCodes.Ldind_I8);
-                       else if (type == TypeManager.char_type)
-                               ig.Emit (OpCodes.Ldind_U2);
-                       else if (type == TypeManager.short_type)
-                               ig.Emit (OpCodes.Ldind_I2);
-                       else if (type == TypeManager.ushort_type)
-                               ig.Emit (OpCodes.Ldind_U2);
-                       else if (type == TypeManager.float_type)
-                               ig.Emit (OpCodes.Ldind_R4);
-                       else if (type == TypeManager.double_type)
-                               ig.Emit (OpCodes.Ldind_R8);
-                       else if (type == TypeManager.byte_type)
-                               ig.Emit (OpCodes.Ldind_U1);
-                       else if (type == TypeManager.sbyte_type || type == TypeManager.bool_type)
-                               ig.Emit (OpCodes.Ldind_I1);
-                       else if (type == TypeManager.intptr_type)
-                               ig.Emit (OpCodes.Ldind_I);
-                       else
-                               ig.Emit (OpCodes.Ldind_Ref);
+                       LoadFromPtr (ig, type, true);
                }
 
                public void EmitAssign (EmitContext ec, Expression source)
@@ -3311,6 +3330,13 @@ namespace Mono.CSharp {
                        if (method is MethodInfo)
                                type = ((MethodInfo)method).ReturnType;
 
+                       if (type.IsPointer){
+                               if (!ec.InUnsafe){
+                                       UnsafeError (loc);
+                                       return null;
+                               }
+                       }
+                       
                        eclass = ExprClass.Value;
                        return this;
                }
@@ -3989,23 +4015,8 @@ namespace Mono.CSharp {
 
                        int count = ArrayData.Count;
 
-                       if (underlying_type == TypeManager.int32_type ||
-                           underlying_type == TypeManager.uint32_type ||
-                           underlying_type == TypeManager.float_type)
-                               factor = 4;
-                       else if (underlying_type == TypeManager.int64_type ||
-                                underlying_type == TypeManager.uint64_type ||
-                                underlying_type == TypeManager.double_type)
-                               factor = 8;
-                       else if (underlying_type == TypeManager.byte_type ||
-                                underlying_type == TypeManager.sbyte_type ||
-                                underlying_type == TypeManager.bool_type)      
-                               factor = 1;
-                       else if (underlying_type == TypeManager.short_type ||
-                                underlying_type == TypeManager.char_type ||
-                                underlying_type == TypeManager.ushort_type)
-                               factor = 2;
-                       else
+                       factor = GetTypeSize (underlying_type);
+                       if (factor == 0)
                                return null;
 
                        data = new byte [(count * factor + 4) & ~3];
@@ -4383,22 +4394,35 @@ namespace Mono.CSharp {
        /// </summary>
        public class SizeOf : Expression {
                public readonly string QueriedType;
+               Type type_queried;
+               Location loc;
                
-               public SizeOf (string queried_type)
+               public SizeOf (string queried_type, Location l)
                {
                        this.QueriedType = queried_type;
+                       loc = l;
                }
 
                public override Expression DoResolve (EmitContext ec)
                {
-                       // FIXME: Implement;
-                       throw new Exception ("Unimplemented");
-                       // return this;
+                       type_queried = RootContext.LookupType (
+                               ec.TypeContainer, QueriedType, false, loc);
+                       if (type_queried == null)
+                               return null;
+
+                       type = TypeManager.int32_type;
+                       eclass = ExprClass.Value;
+                       return this;
                }
 
                public override void Emit (EmitContext ec)
                {
-                       throw new Exception ("Implement me");
+                       int size = GetTypeSize (type_queried);
+
+                       if (size == 0)
+                               ec.ig.Emit (OpCodes.Sizeof, type_queried);
+                       else
+                               IntConstant.EmitInt (ec.ig, size);
                }
        }
 
@@ -4516,6 +4540,7 @@ namespace Mono.CSharp {
                                        if (c != null) {
                                                object o = c.LookupConstantValue (ec);
                                                object real_value = ((Constant) c.Expr).GetValue ();
+
                                                return Constantify (real_value, fi.FieldType);
                                        }
                                }
@@ -4554,6 +4579,11 @@ namespace Mono.CSharp {
                                        
                                        return exp;
                                }
+
+                               if (fi.FieldType.IsPointer && !ec.InUnsafe){
+                                       UnsafeError (loc);
+                                       return null;
+                               }
                                
                                if (left is TypeExpr){
                                        // and refers to a type name or an 
@@ -4688,6 +4718,9 @@ namespace Mono.CSharp {
                        }
                                        
                        //
+                       // TODO: I mailed Ravi about this, and apparently we can get rid
+                       // of this and put it in the right place.
+                       // 
                        // Handle enums here when they are in transit.
                        // Note that we cannot afford to hit MemberLookup in this case because
                        // it will fail to find any members at all
@@ -4708,6 +4741,13 @@ namespace Mono.CSharp {
                                }
                        }
 
+                       if (expr_type.IsPointer){
+                               Report.Error (23, loc,
+                                             "The `.' operator can not be applied to pointer operands (" +
+                                             TypeManager.CSharpName (expr_type) + ")");
+                               return null;
+                       }
+                       
                        member_lookup = MemberLookup (ec, expr_type, Identifier, loc);
 
                        if (member_lookup == null){
@@ -4909,6 +4949,11 @@ namespace Mono.CSharp {
                                return null;
                        }
                        type = t.GetElementType ();
+                       if (type.IsPointer && !ec.InUnsafe){
+                               UnsafeError (ea.loc);
+                               return null;
+                       }
+                       
                        eclass = ExprClass.Variable;
 
                        return this;
@@ -5221,6 +5266,11 @@ namespace Mono.CSharp {
                        }
 
                        type = get.ReturnType;
+                       if (type.IsPointer && !ec.InUnsafe){
+                               UnsafeError (ea.loc);
+                               return null;
+                       }
+                       
                        eclass = ExprClass.IndexerAccess;
                        return this;
                }
@@ -5472,7 +5522,7 @@ namespace Mono.CSharp {
                                return null;
 
                        if (!ec.InUnsafe && type.IsPointer){
-                               Report.Error (214, loc, "Pointers can only be used in an unsafe context");
+                               UnsafeError (loc);
                                return null;
                        }
                        
index 0cfe47f617b91ec3c48cff264a8932a5063eefbb..3d430d29c2ce848e8bf91f45601872f2ced5afdf 100755 (executable)
@@ -11,8 +11,10 @@ TEST_SOURCES = \
        test-41 test-42 test-43 test-44 test-45 test-46 test-47 test-48 test-49 test-50 \
        test-51 test-52 test-53 test-54 test-55 test-56 test-57         test-59         \
        test-61 test-62 test-63 test-64 test-65 test-66 test-67 test-68 test-69 test-70 \
-       test-71 test-72
+       test-71 test-72 
 
+UNSAFE_SOURCES = \
+       unsafe-1
 
 TEST_NOPASS = \
        test-29 test-38 
@@ -31,6 +33,19 @@ test-compiler:
                fi \
        done
 
+test-unsafe:
+       for i in $(UNSAFE_SOURCES); do \
+               if $(MCS) --unsafe $$i.cs > /dev/null; then \
+                       if ./$$i.exe; then \
+                               echo $$i: ok; \
+                       else \
+                               echo test $$i failed; exit; \
+                       fi; \
+               else \
+                       echo compiler failed on $$i;   exit; \
+               fi \
+       done
+
 test-jit:
        for i in $(TEST_SOURCES:.cs=.exe); do \
                if mono ./$$i.exe; then \
index 9b9d016b26dda9648578a1a024050e4a5190a525..ee98f85ceea115815240b245d57cee1493d2f2f0 100644 (file)
@@ -3,14 +3,17 @@ CSCFLAGS=/nologo /debug+ /debug:full
 
 windows: verifier.exe CorCompare.exe EnumCheck.exe IFaceDisco.exe
 
-linux: verifier.exe CorCompare.exe EnumCheck.exe IFaceDisco.exe
+linux: verifier.exe CorCompare.exe EnumCheck.exe IFaceDisco.exe update
 
 verifier.exe: verifier.cs
        $(CSC) $(CSCFLAGS) verifier.cs
 
 CorCompare.exe: CorCompare.cs
        $(CSC) $(CSCFLAGS) CorCompare.cs XMLUtil.cs
+
+update: CorCompare.exe
        ./CorCompare.exe ../class/lib/corlib_cmp.dll > ../../mono/status/cormissing.xml
+       ./CorCompare.exe -t ../class/lib/corlib_cmp.dll > ../../mono/doc/pending-classes.in
 
 EnumCheck.exe:
        $(CSC) $(CSCFLAGS) /out:EnumCheck.exe EnumCheck.cs