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
+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
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
----
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
| sizeof_expression
| checked_expression
| unchecked_expression
+ | pointer_member_access
+ // TODO: pointer_element_access
+ // TODO: sizeof-expression
;
literal
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");
}
;
+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
| lock_statement
| using_statement
| unsafe_statement
+ | fixed_statement
;
empty_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
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
if (parent.UnsafeContext)
return true;
- Report.Error (214, Location, "Pointers can only be used in an unsafe context");
+ Expression.UnsafeError (Location);
return false;
}
}
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){
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
}
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>
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);
}
}
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);
}
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;
}
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 = "
(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)
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,
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)
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)
// 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)
if (method is MethodInfo)
type = ((MethodInfo)method).ReturnType;
+ if (type.IsPointer){
+ if (!ec.InUnsafe){
+ UnsafeError (loc);
+ return null;
+ }
+ }
+
eclass = ExprClass.Value;
return this;
}
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];
/// </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);
}
}
if (c != null) {
object o = c.LookupConstantValue (ec);
object real_value = ((Constant) c.Expr).GetValue ();
+
return Constantify (real_value, fi.FieldType);
}
}
return exp;
}
+
+ if (fi.FieldType.IsPointer && !ec.InUnsafe){
+ UnsafeError (loc);
+ return null;
+ }
if (left is TypeExpr){
// and refers to a type name or an
}
//
+ // 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
}
}
+ 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){
return null;
}
type = t.GetElementType ();
+ if (type.IsPointer && !ec.InUnsafe){
+ UnsafeError (ea.loc);
+ return null;
+ }
+
eclass = ExprClass.Variable;
return this;
}
type = get.ReturnType;
+ if (type.IsPointer && !ec.InUnsafe){
+ UnsafeError (ea.loc);
+ return null;
+ }
+
eclass = ExprClass.IndexerAccess;
return this;
}
return null;
if (!ec.InUnsafe && type.IsPointer){
- Report.Error (214, loc, "Pointers can only be used in an unsafe context");
+ UnsafeError (loc);
return null;
}
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
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 \
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