X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fconst.cs;h=2588ab92aac252b9fc079d82917a265f45d29729;hb=9852c2cbe6f73daa670b333daf70c01d96c2261a;hp=2e562ff2fe589eec44571e692f6fa6c0795a5bbe;hpb=94ce5c5aaf912e55f106bbf3250612b02ac850b5;p=mono.git diff --git a/mcs/mcs/const.cs b/mcs/mcs/const.cs index 2e562ff2fe5..2588ab92aac 100644 --- a/mcs/mcs/const.cs +++ b/mcs/mcs/const.cs @@ -20,12 +20,14 @@ namespace Mono.CSharp { { void CheckObsoleteness (Location loc); bool ResolveValue (); - Constant Value { get; } + Constant CreateConstantReference (Location loc); } - public class Const : FieldMember, IConstant { - Constant value; + public class Const : FieldBase, IConstant { + protected Constant value; bool in_transit; + bool resolved; + bool define_called; public const int AllowedModifiers = Modifiers.NEW | @@ -34,7 +36,7 @@ namespace Mono.CSharp { Modifiers.INTERNAL | Modifiers.PRIVATE; - public Const (TypeContainer parent, Expression constant_type, string name, + public Const (DeclSpace parent, Expression constant_type, string name, Expression expr, int mod_flags, Attributes attrs, Location loc) : base (parent, constant_type, mod_flags, AllowedModifiers, new MemberName (name, loc), attrs) @@ -48,7 +50,7 @@ namespace Mono.CSharp { // Constant.Define can be called when the parent type hasn't yet been populated // and it's base types need not have been populated. So, we defer this check // to the second time Define () is called on this member. - if (Parent.BaseCache == null) + if (Parent.PartialContainer.BaseCache == null) return true; return base.CheckBase (); } @@ -58,34 +60,63 @@ namespace Mono.CSharp { /// public override bool Define () { - // Make Define () idempotent, but ensure that the error check happens. - if (FieldBuilder != null) - return base.CheckBase (); + // Because constant define can be called from other class + if (define_called) { + CheckBase (); + return FieldBuilder != null; + } + + define_called = true; if (!base.Define ()) return false; Type ttype = MemberType; + if (!IsConstantTypeValid (ttype)) { + Error_InvalidConstantType (ttype, Location); + return false; + } + + // If the constant is private then we don't need any field the + // value is already inlined and cannot be referenced + //if ((ModFlags & Modifiers.PRIVATE) != 0 && RootContext.Optimize) + // return true; + while (ttype.IsArray) - ttype = TypeManager.GetElementType (ttype); + ttype = TypeManager.GetElementType (ttype); FieldAttributes field_attr = FieldAttributes.Static | Modifiers.FieldAttr (ModFlags); // Decimals cannot be emitted into the constant blob. So, convert to 'readonly'. if (ttype == TypeManager.decimal_type) { field_attr |= FieldAttributes.InitOnly; - Parent.RegisterFieldForInitialization (this); - } - else { + } else { field_attr |= FieldAttributes.Literal; } FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType, field_attr); - TypeManager.RegisterConstant (FieldBuilder, this); + if (ttype == TypeManager.decimal_type) + Parent.PartialContainer.RegisterFieldForInitialization (this, + new FieldInitializer (FieldBuilder, initializer, Parent)); + return true; } - + + public static bool IsConstantTypeValid (Type t) + { + if (TypeManager.IsBuiltinOrEnum (t)) + return true; + + if (t.IsPointer || t.IsValueType) + return false; + + if (TypeManager.IsGenericParameter (t)) + return false; + + return true; + } + /// /// Emits the field value by evaluating the expression /// @@ -94,6 +125,9 @@ namespace Mono.CSharp { if (!ResolveValue ()) return; + if (FieldBuilder == null) + return; + if (value.Type == TypeManager.decimal_type) { Decimal d = ((DecimalConstant)value).Value; int[] bits = Decimal.GetBits (d); @@ -119,46 +153,67 @@ namespace Mono.CSharp { mc.GetSignatureForError ()); } + public static void Error_ConstantCanBeInitializedWithNullOnly (Location loc, string name) + { + Report.Error (134, loc, "`{0}': the constant of reference type other than string can only be initialized with null", + name); + } + + public static void Error_InvalidConstantType (Type t, Location loc) + { + Report.Error (283, loc, "The type `{0}' cannot be declared const", TypeManager.CSharpName (t)); + } + #region IConstant Members public bool ResolveValue () { - if (value != null) - return true; + if (resolved) + return value != null; SetMemberIsUsed (); if (in_transit) { Error_CyclicDeclaration (this); // Suppress cyclic errors value = New.Constantify (MemberType); + resolved = true; return false; } in_transit = true; - EmitContext ec = new EmitContext (Parent, Location, null, MemberType, ModFlags); - value = initializer.ResolveAsConstant (ec, this); + // TODO: IResolveContext here + EmitContext ec = new EmitContext ( + this, Parent, Location, null, MemberType, ModFlags); + ec.InEnumContext = this is EnumMember; + value = DoResolveValue (ec); in_transit = false; + resolved = true; + return value != null; + } + protected virtual Constant DoResolveValue (EmitContext ec) + { + Constant value = initializer.ResolveAsConstant (ec, this); if (value == null) - return false; - - value = value.ToType (MemberType, Location); - if (value == null) - return false; + return null; - if (!MemberType.IsValueType && MemberType != TypeManager.string_type && !value.IsDefaultValue) { - Report.Error (134, Location, "`{0}': A const of reference other than string can only be initialized with null", - GetSignatureForError ()); - return false; + Constant c = value.ConvertImplicitly (MemberType); + if (c == null) { + if (!MemberType.IsValueType && MemberType != TypeManager.string_type && !value.IsDefaultValue) + Error_ConstantCanBeInitializedWithNullOnly (Location, GetSignatureForError ()); + else + value.Error_ValueCannotBeConverted (null, Location, MemberType, false); } - return true; + return c; } - public Constant Value { - get { - return value; - } + public virtual Constant CreateConstantReference (Location loc) + { + if (value == null) + return null; + + return Constant.CreateConstant (value.Type, value.GetValue(), loc); } #endregion @@ -167,14 +222,14 @@ namespace Mono.CSharp { public class ExternalConstant : IConstant { FieldInfo fi; - Constant value; + object value; public ExternalConstant (FieldInfo fi) { this.fi = fi; } - private ExternalConstant (FieldInfo fi, Constant value): + private ExternalConstant (FieldInfo fi, object value): this (fi) { this.value = value; @@ -195,7 +250,7 @@ namespace Mono.CSharp { return null; IConstant ic = new ExternalConstant (fi, - new DecimalConstant (((System.Runtime.CompilerServices.DecimalConstantAttribute) attrs [0]).Value, Location.Null)); + ((System.Runtime.CompilerServices.DecimalConstantAttribute) attrs [0]).Value); return ic; } @@ -217,20 +272,13 @@ namespace Mono.CSharp { if (value != null) return true; - if (fi.DeclaringType.IsEnum) { - value = Expression.Constantify (fi.GetValue (fi), TypeManager.EnumToUnderlying (fi.FieldType)); - value = new EnumConstant (value, fi.DeclaringType); - return true; - } - - value = Expression.Constantify (fi.GetValue (fi), fi.FieldType); + value = fi.GetValue (fi); return true; } - public Constant Value { - get { - return value; - } + public Constant CreateConstantReference (Location loc) + { + return Constant.CreateConstant (fi.FieldType, value, loc); } #endregion