X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fcodegen.cs;h=af6d336ad482c243e386e998a898f30e03de6a74;hb=c4d8d7c2beddee9f43a7e99d794ef92341238b2c;hp=1411b756969016fafa8637f4f10e6796d6c982db;hpb=23029a245bd3e4d971d6c6753bdad72ca8aa2f19;p=mono.git diff --git a/mcs/mcs/codegen.cs b/mcs/mcs/codegen.cs index 1411b756969..af6d336ad48 100644 --- a/mcs/mcs/codegen.cs +++ b/mcs/mcs/codegen.cs @@ -7,7 +7,16 @@ // (C) 2001, 2002, 2003 Ximian, Inc. // (C) 2004 Novell, Inc. // + +// +// Please leave this defined on SVN: The idea is that when we ship the +// compiler to end users, if the compiler crashes, they have a chance +// to narrow down the problem. +// +// Only remove it if you need to debug locally on your tree. +// //#define PRODUCTION + using System; using System.IO; using System.Collections; @@ -86,7 +95,7 @@ namespace Mono.CSharp { // if (SymbolWriter == null) { Report.Warning ( - -18, "Could not find the symbol writer assembly (Mono.CompilerServices.SymbolWriter.dll). This is normally an installation problem. Please make sure to compile and install the mcs/class/Mono.CompilerServices.SymbolWriter directory."); + -18, 1, "Could not find the symbol writer assembly (Mono.CompilerServices.SymbolWriter.dll). This is normally an installation problem. Please make sure to compile and install the mcs/class/Mono.CompilerServices.SymbolWriter directory."); return; } } @@ -104,11 +113,11 @@ namespace Mono.CSharp { if (an.KeyPair != null) { // If we are going to strong name our assembly make // sure all its refs are strong named - foreach (Assembly a in TypeManager.GetAssemblies ()) { + foreach (Assembly a in RootNamespace.Global.Assemblies) { AssemblyName ref_name = a.GetName (); byte [] b = ref_name.GetPublicKeyToken (); if (b == null || b.Length == 0) { - Report.Warning (1577, "Assembly generation failed " + + Report.Error (1577, "Assembly generation failed " + "-- Referenced assembly '" + ref_name.Name + "' does not have a strong name."); @@ -140,6 +149,12 @@ namespace Mono.CSharp { return false; } +#if GMCS_SOURCE + // Get the complete AssemblyName from the builder + // (We need to get the public key and token) + Assembly.Name = Assembly.Builder.GetName (); +#endif + // // Pass a path-less name to DefineDynamicModule. Wonder how // this copes with output in different directories then. @@ -161,6 +176,9 @@ namespace Mono.CSharp { { try { Assembly.Builder.Save (Basename (name)); + + if (SymbolWriter != null) + SymbolWriter.WriteSymbolFile (); } catch (COMException) { if ((RootContext.StrongNameKeyFile == null) || (!RootContext.StrongNameDelaySign)) @@ -177,40 +195,79 @@ namespace Mono.CSharp { catch (System.UnauthorizedAccessException ua) { Report.Error (16, "Could not write to file `"+name+"', cause: " + ua.Message); } - - if (SymbolWriter != null) - SymbolWriter.WriteSymbolFile (); } } + + public interface IResolveContext + { + DeclSpace DeclContainer { get; } + bool IsInObsoleteScope { get; } + bool IsInUnsafeScope { get; } + + // the declcontainer to lookup for type-parameters. Should only use LookupGeneric on it. + // + // FIXME: This is somewhat of a hack. We don't need a full DeclSpace for this. We just need the + // current type parameters in scope. IUIC, that will require us to rewrite GenericMethod. + // Maybe we can replace this with a 'LookupGeneric (string)' instead, but we'll have to + // handle generic method overrides differently + DeclSpace GenericDeclContainer { get; } + } + /// /// An Emit Context is created for each body of code (from methods, /// properties bodies, indexer bodies or constructor bodies) /// - public class EmitContext { - public readonly DeclSpace DeclSpace; + public class EmitContext : IResolveContext { + + DeclSpace declSpace; public DeclSpace TypeContainer; public ILGenerator ig; - /// - /// This variable tracks the `checked' state of the compilation, - /// it controls whether we should generate code that does overflow - /// checking, or if we generate code that ignores overflows. - /// - /// The default setting comes from the command line option to generate - /// checked or unchecked code plus any source code changes using the - /// checked/unchecked statements or expressions. Contrast this with - /// the ConstantCheckState flag. - /// - - public bool CheckState; - - /// - /// The constant check state is always set to `true' and cant be changed - /// from the command line. The source code can change this setting with - /// the `checked' and `unchecked' statements and expressions. - /// - public bool ConstantCheckState; + [Flags] + public enum Flags : byte { + /// + /// This flag tracks the `checked' state of the compilation, + /// it controls whether we should generate code that does overflow + /// checking, or if we generate code that ignores overflows. + /// + /// The default setting comes from the command line option to generate + /// checked or unchecked code plus any source code changes using the + /// checked/unchecked statements or expressions. Contrast this with + /// the ConstantCheckState flag. + /// + CheckState = 1 << 0, + + /// + /// The constant check state is always set to `true' and cant be changed + /// from the command line. The source code can change this setting with + /// the `checked' and `unchecked' statements and expressions. + /// + ConstantCheckState = 1 << 1, + + AllCheckStateFlags = CheckState | ConstantCheckState, + + /// + /// Whether we are inside an unsafe block + /// + InUnsafe = 1 << 2, + + InCatch = 1 << 3, + InFinally = 1 << 4, + + /// + /// Whether control flow analysis is enabled + /// + DoFlowAnalysis = 1 << 5, + + /// + /// Whether control flow analysis is disabled on structs + /// (only meaningful when DoFlowAnalysis is set) + /// + OmitStructFlowAnalysis = 1 << 6 + } + + Flags flags; /// /// Whether we are emitting code inside a static or instance method @@ -236,7 +293,7 @@ namespace Mono.CSharp { /// The value that is allowed to be returned or NULL if there is no /// return type. /// - public Type ReturnType; + public readonly Type ReturnType; /// /// Points to the Type (extracted from the TypeContainer) that @@ -249,11 +306,6 @@ namespace Mono.CSharp { /// public bool IsConstructor; - /// - /// Whether we're control flow analysis enabled - /// - public bool DoFlowAnalysis; - /// /// Keeps track of the Type to LocalBuilder temporary storage created /// to store structures (used to compute the address of the structure @@ -288,21 +340,11 @@ namespace Mono.CSharp { public bool IsLastStatement; - /// - /// Whether we are inside an unsafe block - /// - public bool InUnsafe; - /// /// Whether we are in a `fixed' initialization /// public bool InFixedInitializer; - public bool InRefOutArgumentResolving; - - public bool InCatch; - public bool InFinally; - /// /// Whether we are inside an anonymous method. /// @@ -323,23 +365,14 @@ namespace Mono.CSharp { /// public bool InEnumContext; - /// - /// Anonymous methods can capture local variables and fields, - /// this object tracks it. It is copied from the TopLevelBlock - /// field. - /// - public CaptureContext capture_context; - - /// - /// Trace when method is called and is obsolete then this member suppress message - /// when call is inside next [Obsolete] method or type. - /// - public bool TestObsoleteMethodUsage = true; + public readonly IResolveContext ResolveContext; /// /// The current iterator /// - public Iterator CurrentIterator; + public Iterator CurrentIterator { + get { return CurrentAnonymousMethod as Iterator; } + } /// /// Whether we are in the resolving stage or not @@ -349,7 +382,11 @@ namespace Mono.CSharp { Resolving, Emitting } + + public static EmitContext TempEc; + bool isAnonymousMethodAllowed = true; + Phase current_phase; FlowBranching current_flow_branching; @@ -358,19 +395,26 @@ namespace Mono.CSharp { public override string ToString () { - return String.Format ("EmitContext ({0}:{1}:{2})", id, - CurrentIterator, capture_context, loc); + return String.Format ("EmitContext ({0}:{1})", id, + CurrentAnonymousMethod, loc); } - public EmitContext (DeclSpace parent, DeclSpace ds, Location l, ILGenerator ig, + public EmitContext (IResolveContext rc, DeclSpace parent, DeclSpace ds, Location l, ILGenerator ig, Type return_type, int code_flags, bool is_constructor) { + this.ResolveContext = rc; this.ig = ig; TypeContainer = parent; - DeclSpace = ds; - CheckState = RootContext.Checked; - ConstantCheckState = true; + this.declSpace = ds; + if (RootContext.Checked) + flags |= Flags.CheckState; + flags |= Flags.ConstantCheckState; + +#if GMCS_SOURCE + if ((return_type is TypeBuilder) && return_type.IsGenericTypeDefinition) + throw new InternalErrorException (); +#endif IsStatic = (code_flags & Modifiers.STATIC) != 0; MethodIsStatic = IsStatic; @@ -380,14 +424,12 @@ namespace Mono.CSharp { CurrentBlock = null; CurrentFile = 0; current_phase = Phase.Created; - + if (parent != null){ // Can only be null for the ResolveType contexts. ContainerType = parent.TypeBuilder; - if (parent.UnsafeContext) - InUnsafe = true; - else - InUnsafe = (code_flags & Modifiers.UNSAFE) != 0; + if (rc.IsInUnsafeScope) + flags |= Flags.InUnsafe; } loc = l; @@ -395,30 +437,105 @@ namespace Mono.CSharp { ReturnType = null; } - public EmitContext (TypeContainer tc, Location l, ILGenerator ig, + public EmitContext (IResolveContext rc, DeclSpace ds, Location l, ILGenerator ig, Type return_type, int code_flags, bool is_constructor) - : this (tc, tc, l, ig, return_type, code_flags, is_constructor) + : this (rc, ds, ds, l, ig, return_type, code_flags, is_constructor) { } - public EmitContext (TypeContainer tc, Location l, ILGenerator ig, + public EmitContext (IResolveContext rc, DeclSpace ds, Location l, ILGenerator ig, Type return_type, int code_flags) - : this (tc, tc, l, ig, return_type, code_flags, false) + : this (rc, ds, ds, l, ig, return_type, code_flags, false) { } - public FlowBranching CurrentBranching { - get { - return current_flow_branching; - } + public DeclSpace DeclContainer { + get { return declSpace; } + set { declSpace = value; } } - public bool HaveCaptureInfo { - get { - return capture_context != null; + public DeclSpace GenericDeclContainer { + get { return DeclContainer; } + } + + public bool CheckState { + get { return (flags & Flags.CheckState) != 0; } + } + + public bool ConstantCheckState { + get { return (flags & Flags.ConstantCheckState) != 0; } + } + + public bool InUnsafe { + get { return (flags & Flags.InUnsafe) != 0; } + } + + public bool InCatch { + get { return (flags & Flags.InCatch) != 0; } + } + + public bool InFinally { + get { return (flags & Flags.InFinally) != 0; } + } + + public bool DoFlowAnalysis { + get { return (flags & Flags.DoFlowAnalysis) != 0; } + } + + public bool OmitStructFlowAnalysis { + get { return (flags & Flags.OmitStructFlowAnalysis) != 0; } + } + + // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements + // it's public so that we can use a struct at the callsite + public struct FlagsHandle : IDisposable + { + EmitContext ec; + Flags invmask, oldval; + internal FlagsHandle (EmitContext ec, Flags mask, Flags val) + { + this.ec = ec; + invmask = ~mask; + oldval = ec.flags & mask; + ec.flags = (ec.flags & invmask) | (val & mask); + } + public void Dispose () + { + ec.flags = (ec.flags & invmask) | oldval; } } + // Temporarily set all the given flags to the given value. Should be used in an 'using' statement + public FlagsHandle With (Flags bits, bool enable) + { + return new FlagsHandle (this, bits, enable ? bits : 0); + } + + public FlagsHandle WithFlowAnalysis (bool do_flow_analysis, bool omit_struct_analysis) + { + Flags newflags = + (do_flow_analysis ? Flags.DoFlowAnalysis : 0) | + (omit_struct_analysis ? Flags.OmitStructFlowAnalysis : 0); + return new FlagsHandle (this, Flags.DoFlowAnalysis | Flags.OmitStructFlowAnalysis, newflags); + } + + public bool IsInObsoleteScope { + get { return ResolveContext.IsInObsoleteScope; } + } + + public bool IsInUnsafeScope { + get { return InUnsafe || ResolveContext.IsInUnsafeScope; } + } + + public bool IsAnonymousMethodAllowed { + get { return isAnonymousMethodAllowed; } + set { isAnonymousMethodAllowed = value; } + } + + public FlowBranching CurrentBranching { + get { return current_flow_branching; } + } + // // Starts a new code branching. This inherits the state of all local // variables and parameters from the current branching. @@ -442,7 +559,7 @@ namespace Mono.CSharp { else type = FlowBranching.BranchingType.Block; - DoFlowAnalysis = true; + flags |= Flags.DoFlowAnalysis; current_flow_branching = FlowBranching.CreateBranching ( CurrentBranching, type, block, block.StartLocation); @@ -451,8 +568,21 @@ namespace Mono.CSharp { public FlowBranchingException StartFlowBranching (ExceptionStatement stmt) { - FlowBranchingException branching = new FlowBranchingException ( - CurrentBranching, stmt); + FlowBranchingException branching = new FlowBranchingException (CurrentBranching, stmt); + current_flow_branching = branching; + return branching; + } + + public FlowBranchingLabeled StartFlowBranching (LabeledStatement stmt) + { + FlowBranchingLabeled branching = new FlowBranchingLabeled (CurrentBranching, stmt); + current_flow_branching = branching; + return branching; + } + + public FlowBranchingToplevel StartFlowBranching (ToplevelBlock stmt) + { + FlowBranchingToplevel branching = new FlowBranchingToplevel (CurrentBranching, stmt); current_flow_branching = branching; return branching; } @@ -489,84 +619,17 @@ namespace Mono.CSharp { current_flow_branching = current_flow_branching.Parent; } - public void CaptureVariable (LocalInfo li) - { - capture_context.AddLocal (CurrentAnonymousMethod, li); - li.IsCaptured = true; - } - - public void CaptureParameter (string name, Type t, int idx) - { - capture_context.AddParameter (this, CurrentAnonymousMethod, name, t, idx); - } - - public void CaptureThis () - { - capture_context.CaptureThis (); - } - - - // - // Use to register a field as captured - // - public void CaptureField (FieldExpr fe) - { - capture_context.AddField (fe); - } - - // - // Whether anonymous methods have captured variables - // - public bool HaveCapturedVariables () - { - if (capture_context != null) - return capture_context.HaveCapturedVariables; - return false; - } - - // - // Whether anonymous methods have captured fields or this. - // - public bool HaveCapturedFields () - { - if (capture_context != null) - return capture_context.HaveCapturedFields; - return false; - } - - // - // Emits the instance pointer for the host method - // - public void EmitMethodHostInstance (EmitContext target, AnonymousMethod am) - { - if (capture_context != null) - capture_context.EmitMethodHostInstance (target, am); - else if (IsStatic) - target.ig.Emit (OpCodes.Ldnull); - else - target.ig.Emit (OpCodes.Ldarg_0); - } - - // - // Returns whether the `local' variable has been captured by an anonymous - // method - // - public bool IsCaptured (LocalInfo local) + public bool MustCaptureVariable (LocalInfo local) { - return capture_context.IsCaptured (local); - } - - public bool IsParameterCaptured (string name) - { - if (capture_context != null) - return capture_context.IsParameterCaptured (name); - return false; + if (CurrentAnonymousMethod == null) + return false; + if (CurrentAnonymousMethod.IsIterator) + return true; + return local.Block.Toplevel != CurrentBlock.Toplevel; } - public void EmitMeta (ToplevelBlock b, InternalParameters ip) + public void EmitMeta (ToplevelBlock b) { - if (capture_context != null) - capture_context.EmitAnonymousHelperClasses (this); b.EmitMeta (this); if (HasReturnLabel) @@ -578,15 +641,15 @@ namespace Mono.CSharp { // currently can not cope with ig == null during resolve (which must // be fixed for switch statements to work on anonymous methods). // - public void EmitTopBlock (IMethodData md, ToplevelBlock block, InternalParameters ip) + public void EmitTopBlock (IMethodData md, ToplevelBlock block) { if (block == null) return; bool unreachable; - if (ResolveTopBlock (null, block, ip, md, out unreachable)){ - EmitMeta (block, ip); + if (ResolveTopBlock (null, block, md.ParameterInfo, md, out unreachable)){ + EmitMeta (block); current_phase = Phase.Emitting; EmitResolvedTopBlock (block, unreachable); @@ -596,7 +659,7 @@ namespace Mono.CSharp { bool resolved; public bool ResolveTopBlock (EmitContext anonymous_method_host, ToplevelBlock block, - InternalParameters ip, IMethodData md, out bool unreachable) + Parameters ip, IMethodData md, out bool unreachable) { current_phase = Phase.Resolving; @@ -605,9 +668,7 @@ namespace Mono.CSharp { if (resolved) return true; - capture_context = block.CaptureContext; - - if (!Location.IsNull (loc)) + if (!loc.IsNull) CurrentFile = loc.File; #if PRODUCTION @@ -616,42 +677,40 @@ namespace Mono.CSharp { if (!block.ResolveMeta (this, ip)) return false; - bool old_do_flow_analysis = DoFlowAnalysis; - DoFlowAnalysis = true; + if ((md != null) && (md.Iterator != null)) { + if (!md.Iterator.Resolve (this)) + return false; + } + using (this.With (EmitContext.Flags.DoFlowAnalysis, true)) { + FlowBranchingToplevel top_level; if (anonymous_method_host != null) - current_flow_branching = FlowBranching.CreateBranching ( - anonymous_method_host.CurrentBranching, - FlowBranching.BranchingType.Block, block, loc); + top_level = new FlowBranchingToplevel (anonymous_method_host.CurrentBranching, block); else - current_flow_branching = block.TopLevelBranching; + top_level = block.TopLevelBranching; - if (!block.Resolve (this)) { - current_flow_branching = null; - DoFlowAnalysis = old_do_flow_analysis; - return false; - } - - FlowBranching.Reachability reachability = current_flow_branching.MergeTopBlock (); + current_flow_branching = top_level; + bool ok = block.Resolve (this); current_flow_branching = null; - - DoFlowAnalysis = old_do_flow_analysis; - if (reachability.AlwaysReturns || - reachability.AlwaysThrows || - reachability.IsUnreachable) + if (!ok) + return false; + + FlowBranching.Reachability reachability = top_level.End (); + if (reachability.IsUnreachable) unreachable = true; + } #if PRODUCTION } catch (Exception e) { - Console.WriteLine ("Exception caught by the compiler while compiling:"); - Console.WriteLine (" Block that caused the problem begin at: " + loc); - - if (CurrentBlock != null){ - Console.WriteLine (" Block being compiled: [{0},{1}]", - CurrentBlock.StartLocation, CurrentBlock.EndLocation); - } - Console.WriteLine (e.GetType ().FullName + ": " + e.Message); - throw; + Console.WriteLine ("Exception caught by the compiler while compiling:"); + Console.WriteLine (" Block that caused the problem begin at: " + loc); + + if (CurrentBlock != null){ + Console.WriteLine (" Block being compiled: [{0},{1}]", + CurrentBlock.StartLocation, CurrentBlock.EndLocation); + } + Console.WriteLine (e.GetType ().FullName + ": " + e.Message); + throw; } #endif @@ -661,12 +720,14 @@ namespace Mono.CSharp { return false; } else if (!CurrentAnonymousMethod.IsIterator) { Report.Error (1643, CurrentAnonymousMethod.Location, "Not all code paths return a value in anonymous method of type `{0}'", - CurrentAnonymousMethod.GetSignatureForError ()); + CurrentAnonymousMethod.GetSignatureForError ()); return false; } } - block.CompleteContexts (); + if (!block.CompleteContexts (this)) + return false; + resolved = true; return true; } @@ -675,10 +736,10 @@ namespace Mono.CSharp { { if (block != null) block.Emit (this); - + if (HasReturnLabel) ig.MarkLabel (ReturnLabel); - + if (return_value != null){ ig.Emit (OpCodes.Ldloc, return_value); ig.Emit (OpCodes.Ret); @@ -707,12 +768,6 @@ namespace Mono.CSharp { ig.Emit (OpCodes.Ret); } } - - // - // Close pending helper classes if we are the toplevel - // - if (capture_context != null && capture_context.ParentToplevel == null) - capture_context.CloseAnonymousHelperClasses (); } /// @@ -721,13 +776,13 @@ namespace Mono.CSharp { /// public void Mark (Location loc, bool check_file) { - if ((CodeGen.SymbolWriter == null) || Location.IsNull (loc)) + if ((CodeGen.SymbolWriter == null) || loc.IsNull) return; if (check_file && (CurrentFile != loc.File)) return; - CodeGen.SymbolWriter.MarkSequencePoint (ig, loc.Row, 0); + CodeGen.SymbolWriter.MarkSequencePoint (ig, loc.Row, loc.Column); } public void DefineLocalVariable (string name, LocalBuilder builder) @@ -760,58 +815,44 @@ namespace Mono.CSharp { /// public LocalBuilder GetTemporaryLocal (Type t) { - LocalBuilder location = null; - - if (temporary_storage != null){ + if (temporary_storage != null) { object o = temporary_storage [t]; - if (o != null){ - if (o is ArrayList){ - ArrayList al = (ArrayList) o; - - for (int i = 0; i < al.Count; i++){ - if (al [i] != null){ - location = (LocalBuilder) al [i]; - al [i] = null; - break; - } - } - } else - location = (LocalBuilder) o; - if (location != null) - return location; + if (o != null) { + if (o is Stack) { + Stack s = (Stack) o; + o = s.Count == 0 ? null : s.Pop (); + } else { + temporary_storage.Remove (t); + } } + if (o != null) + return (LocalBuilder) o; } - return ig.DeclareLocal (t); } public void FreeTemporaryLocal (LocalBuilder b, Type t) { - if (temporary_storage == null){ + Stack s; + + if (temporary_storage == null) { temporary_storage = new Hashtable (); temporary_storage [t] = b; return; } object o = temporary_storage [t]; - if (o == null){ + if (o == null) { temporary_storage [t] = b; return; } - if (o is ArrayList){ - ArrayList al = (ArrayList) o; - for (int i = 0; i < al.Count; i++){ - if (al [i] == null){ - al [i] = b; - return; - } - } - al.Add (b); - return; + if (o is Stack) { + s = (Stack) o; + } else { + s = new Stack (); + s.Push (o); + temporary_storage [t] = s; } - ArrayList replacement = new ArrayList (); - replacement.Add (o); - temporary_storage.Remove (t); - temporary_storage [t] = replacement; + s.Push (b); } /// @@ -873,54 +914,7 @@ namespace Mono.CSharp { HasReturnLabel = true; } - // - // Emits the proper object to address fields on a remapped - // variable/parameter to field in anonymous-method/iterator proxy classes. - // - public void EmitThis () - { - ig.Emit (OpCodes.Ldarg_0); - if (capture_context != null && CurrentAnonymousMethod != null){ - ScopeInfo si = CurrentAnonymousMethod.Scope; - while (si != null){ - if (si.ParentLink != null) - ig.Emit (OpCodes.Ldfld, si.ParentLink); - if (si.THIS != null){ - ig.Emit (OpCodes.Ldfld, si.THIS); - break; - } - si = si.ParentScope; - } - } - } - - // - // Emits the code necessary to load the instance required - // to access the captured LocalInfo - // - public void EmitCapturedVariableInstance (LocalInfo li) - { - if (capture_context == null) - throw new Exception ("Calling EmitCapturedContext when there is no capture_context"); - - capture_context.EmitCapturedVariableInstance (this, li, CurrentAnonymousMethod); - } - - public void EmitParameter (string name) - { - capture_context.EmitParameter (this, name); - } - - public void EmitAssignParameter (string name, Expression source, bool leave_copy, bool prepare_for_load) - { - capture_context.EmitAssignParameter (this, name, source, leave_copy, prepare_for_load); - } - public void EmitAddressOfParameter (string name) - { - capture_context.EmitAddressOfParameter (this, name); - } - public Expression GetThis (Location loc) { This my_this; @@ -937,7 +931,8 @@ namespace Mono.CSharp { } - public abstract class CommonAssemblyModulClass: Attributable { + public abstract class CommonAssemblyModulClass : Attributable, IResolveContext { + protected CommonAssemblyModulClass (): base (null) { @@ -945,11 +940,14 @@ namespace Mono.CSharp { public void AddAttributes (ArrayList attrs) { - if (OptAttributes == null) { - OptAttributes = new Attributes (attrs); + foreach (Attribute a in attrs) + a.AttachTo (this); + + if (attributes == null) { + attributes = new Attributes (attrs); return; } - OptAttributes.AddAttributes (attrs); + attributes.AddAttributes (attrs); } public virtual void Emit (TypeContainer tc) @@ -957,42 +955,71 @@ namespace Mono.CSharp { if (OptAttributes == null) return; - EmitContext ec = new EmitContext (tc, Mono.CSharp.Location.Null, null, null, 0, false); - OptAttributes.Emit (ec, this); + OptAttributes.Emit (); } - + protected Attribute ResolveAttribute (Type a_type) { - if (OptAttributes == null) - return null; - - // Ensure that we only have GlobalAttributes, since the Search below isn't safe with other types. - if (!OptAttributes.CheckTargets (this)) - return null; - - EmitContext temp_ec = new EmitContext (RootContext.Tree.Types, Mono.CSharp.Location.Null, null, null, 0, false); - Attribute a = OptAttributes.Search (a_type, temp_ec); + Attribute a = OptAttributes.Search (a_type); if (a != null) { - a.Resolve (temp_ec); + a.Resolve (); } return a; } + + public override IResolveContext ResolveContext { + get { return this; } + } + + #region IResolveContext Members + + public DeclSpace DeclContainer { + get { return RootContext.ToplevelTypes; } + } + + public DeclSpace GenericDeclContainer { + get { return DeclContainer; } + } + + public bool IsInObsoleteScope { + get { return false; } + } + + public bool IsInUnsafeScope { + get { return false; } + } + + #endregion } - public class AssemblyClass: CommonAssemblyModulClass { + public class AssemblyClass : CommonAssemblyModulClass { // TODO: make it private and move all builder based methods here public AssemblyBuilder Builder; bool is_cls_compliant; + bool wrap_non_exception_throws; + bool has_extension_method; + public Attribute ClsCompliantAttribute; ListDictionary declarative_security; +#if GMCS_SOURCE + public AssemblyName Name; + MethodInfo add_type_forwarder; + ListDictionary emitted_forwarders; +#endif // Module is here just because of error messages static string[] attribute_targets = new string [] { "assembly", "module" }; public AssemblyClass (): base () { - is_cls_compliant = false; +#if GMCS_SOURCE + wrap_non_exception_throws = true; +#endif + } + + public bool HasExtensionMethods { + set { has_extension_method = value; } } public bool IsClsCompliant { @@ -1001,24 +1028,45 @@ namespace Mono.CSharp { } } + public bool WrapNonExceptionThrows { + get { + return wrap_non_exception_throws; + } + } + public override AttributeTargets AttributeTargets { get { return AttributeTargets.Assembly; } } - public override bool IsClsCompliaceRequired(DeclSpace ds) + public override bool IsClsComplianceRequired () { return is_cls_compliant; } - public void ResolveClsCompliance () + public void Resolve () { - ClsCompliantAttribute = ResolveAttribute (TypeManager.cls_compliant_attribute_type); - if (ClsCompliantAttribute == null) + if (OptAttributes == null) return; - is_cls_compliant = ClsCompliantAttribute.GetClsCompliantAttributeValue (null); + // Ensure that we only have GlobalAttributes, since the Search isn't safe with other types. + if (!OptAttributes.CheckTargets()) + return; + + ClsCompliantAttribute = ResolveAttribute (TypeManager.cls_compliant_attribute_type); + if (ClsCompliantAttribute != null) { + is_cls_compliant = ClsCompliantAttribute.GetClsCompliantAttributeValue (); + } + +#if GMCS_SOURCE + Attribute a = ResolveAttribute (TypeManager.runtime_compatibility_attr_type); + if (a != null) { + object val = a.GetPropertyValue ("WrapNonExceptionThrows"); + if (val != null) + wrap_non_exception_throws = (bool)val; + } +#endif } // fix bug #56621 @@ -1046,7 +1094,7 @@ namespace Mono.CSharp { } } catch (Exception) { - Error_AssemblySigning ("The speficied file `" + RootContext.StrongNameKeyFile + "' is incorrectly encoded"); + Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' is incorrectly encoded"); Environment.Exit (1); } } @@ -1070,12 +1118,12 @@ namespace Mono.CSharp { case "System.Reflection.AssemblyKeyFileAttribute": if (RootContext.StrongNameKeyFile != null) { Report.SymbolRelatedToPreviousError (a.Location, a.Name); - Report.Warning (1616, "Option `{0}' overrides attribute `{1}' given in a source file or added module", + Report.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module", "keyfile", "System.Reflection.AssemblyKeyFileAttribute"); } else { string value = a.GetString (); - if (value != String.Empty) + if (value.Length != 0) RootContext.StrongNameKeyFile = value; } break; @@ -1084,12 +1132,12 @@ namespace Mono.CSharp { case "System.Reflection.AssemblyKeyNameAttribute": if (RootContext.StrongNameKeyContainer != null) { Report.SymbolRelatedToPreviousError (a.Location, a.Name); - Report.Warning (1616, "Option `{0}' overrides attribute `{1}' given in a source file or added module", + Report.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module", "keycontainer", "System.Reflection.AssemblyKeyNameAttribute"); } else { string value = a.GetString (); - if (value != String.Empty) + if (value.Length != 0) RootContext.StrongNameKeyContainer = value; } break; @@ -1152,7 +1200,7 @@ namespace Mono.CSharp { "ECMA key can only be used to delay-sign assemblies"); } else { - Error_AssemblySigning ("The speficied file `" + RootContext.StrongNameKeyFile + "' does not have a private key"); + Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' does not have a private key"); } return null; } @@ -1160,7 +1208,7 @@ namespace Mono.CSharp { } } else { - Error_AssemblySigning ("The speficied file `" + RootContext.StrongNameKeyFile + "' does not exist"); + Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' does not exist"); return null; } return an; @@ -1171,6 +1219,37 @@ namespace Mono.CSharp { Report.Error (1548, "Error during assembly signing. " + text); } +#if GMCS_SOURCE + bool CheckInternalsVisibleAttribute (Attribute a) + { + string assembly_name = a.GetString (); + if (assembly_name.Length == 0) + return false; + + AssemblyName aname = null; + try { + aname = new AssemblyName (assembly_name); + } catch (FileLoadException) { + } catch (ArgumentException) { + } + + // Bad assembly name format + if (aname == null) + Report.Warning (1700, 3, a.Location, "Assembly reference `" + assembly_name + "' is invalid and cannot be resolved"); + // Report error if we have defined Version or Culture + else if (aname.Version != null || aname.CultureInfo != null) + throw new Exception ("Friend assembly `" + a.GetString () + + "' is invalid. InternalsVisibleTo cannot have version or culture specified."); + else if (aname.GetPublicKey () == null && Name.GetPublicKey () != null) { + Report.Error (1726, a.Location, "Friend assembly reference `" + aname.FullName + "' is invalid." + + " Strong named assemblies must specify a public key in their InternalsVisibleTo declarations"); + return false; + } + + return true; + } +#endif + public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder customBuilder) { if (a.Type.IsSubclassOf (TypeManager.security_attr_type) && a.CheckSecurityActionValidity (true)) { @@ -1192,6 +1271,65 @@ namespace Mono.CSharp { } } +#if GMCS_SOURCE + if (a.Type == TypeManager.internals_visible_attr_type && !CheckInternalsVisibleAttribute (a)) + return; + + if (a.Type == TypeManager.type_forwarder_attr_type) { + Type t = a.GetArgumentType (); + if (t == null || TypeManager.HasElementType (t)) { + Report.Error (735, a.Location, "Invalid type specified as an argument for TypeForwardedTo attribute"); + return; + } + + if (emitted_forwarders == null) { + emitted_forwarders = new ListDictionary(); + } else if (emitted_forwarders.Contains(t)) { + Report.SymbolRelatedToPreviousError(((Attribute)emitted_forwarders[t]).Location, null); + Report.Error(739, a.Location, "A duplicate type forward of type `{0}'", + TypeManager.CSharpName(t)); + return; + } + + emitted_forwarders.Add(t, a); + + if (TypeManager.LookupDeclSpace (t) != null) { + Report.SymbolRelatedToPreviousError (t); + Report.Error (729, a.Location, "Cannot forward type `{0}' because it is defined in this assembly", + TypeManager.CSharpName (t)); + return; + } + + if (t.IsNested) { + Report.Error (730, a.Location, "Cannot forward type `{0}' because it is a nested type", + TypeManager.CSharpName (t)); + return; + } + + if (t.IsGenericType) { + Report.Error (733, a.Location, "Cannot forward generic type `{0}'", TypeManager.CSharpName (t)); + return; + } + + if (add_type_forwarder == null) { + add_type_forwarder = typeof (AssemblyBuilder).GetMethod ("AddTypeForwarder", + BindingFlags.NonPublic | BindingFlags.Instance); + + if (add_type_forwarder == null) { + Report.RuntimeMissingSupport (a.Location, "TypeForwardedTo attribute"); + return; + } + } + + add_type_forwarder.Invoke (Builder, new object[] { t }); + return; + } + + if (a.Type == TypeManager.extension_attribute_type) { + a.Error_MisusedExtensionAttribute (); + return; + } +#endif Builder.SetCustomAttribute (customBuilder); } @@ -1199,6 +1337,23 @@ namespace Mono.CSharp { { base.Emit (tc); +#if GMCS_SOURCE + if (has_extension_method) + Builder.SetCustomAttribute (TypeManager.extension_attribute_attr); + + // FIXME: Does this belong inside SRE.AssemblyBuilder instead? + if (OptAttributes == null || !OptAttributes.Contains (TypeManager.runtime_compatibility_attr_type)) { + ConstructorInfo ci = TypeManager.GetConstructor ( + TypeManager.runtime_compatibility_attr_type, Type.EmptyTypes); + PropertyInfo [] pis = new PropertyInfo [1]; + pis [0] = TypeManager.GetProperty ( + TypeManager.runtime_compatibility_attr_type, "WrapNonExceptionThrows"); + object [] pargs = new object [1]; + pargs [0] = true; + Builder.SetCustomAttribute (new CustomAttributeBuilder (ci, new object [0], pis, pargs)); + } +#endif + if (declarative_security != null) { MethodInfo add_permission = typeof (AssemblyBuilder).GetMethod ("AddPermissionRequests", BindingFlags.Instance | BindingFlags.NonPublic); @@ -1230,12 +1385,37 @@ namespace Mono.CSharp { return attribute_targets; } } + + // Wrapper for AssemblyBuilder.AddModule + static MethodInfo adder_method; + static public MethodInfo AddModule_Method { + get { + if (adder_method == null) + adder_method = typeof (AssemblyBuilder).GetMethod ("AddModule", BindingFlags.Instance|BindingFlags.NonPublic); + return adder_method; + } + } + public Module AddModule (string module) + { + MethodInfo m = AddModule_Method; + if (m == null) { + Report.RuntimeMissingSupport (Location.Null, "/addmodule"); + Environment.Exit (1); + } + + try { + return (Module) m.Invoke (Builder, new object [] { module }); + } catch (TargetInvocationException ex) { + throw ex.InnerException; + } + } } - public class ModuleClass: CommonAssemblyModulClass { + public class ModuleClass : CommonAssemblyModulClass { // TODO: make it private and move all builder based methods here public ModuleBuilder Builder; bool m_module_is_unsafe; + bool has_default_charset; public CharSet DefaultCharSet = CharSet.Ansi; public TypeAttributes DefaultCharSetType = TypeAttributes.AnsiClass; @@ -1253,7 +1433,7 @@ namespace Mono.CSharp { } } - public override bool IsClsCompliaceRequired(DeclSpace ds) + public override bool IsClsComplianceRequired () { return CodeGen.Assembly.IsClsCompliant; } @@ -1277,7 +1457,7 @@ namespace Mono.CSharp { { if (a.Type == TypeManager.cls_compliant_attribute_type) { if (CodeGen.Assembly.ClsCompliantAttribute == null) { - Report.Warning (3012, a.Location, "You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking"); + Report.Warning (3012, 1, a.Location, "You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking"); } else if (CodeGen.Assembly.IsClsCompliant != a.GetBoolean ()) { Report.SymbolRelatedToPreviousError (CodeGen.Assembly.ClsCompliantAttribute.Location, CodeGen.Assembly.ClsCompliantAttribute.GetSignatureForError ()); @@ -1289,14 +1469,27 @@ namespace Mono.CSharp { Builder.SetCustomAttribute (customBuilder); } + public bool HasDefaultCharSet { + get { + return has_default_charset; + } + } + /// /// It is called very early therefore can resolve only predefined attributes /// - public void ResolveAttributes () + public void Resolve () { -#if NET_2_0 +#if GMCS_SOURCE + if (OptAttributes == null) + return; + + if (!OptAttributes.CheckTargets()) + return; + Attribute a = ResolveAttribute (TypeManager.default_charset_type); if (a != null) { + has_default_charset = true; DefaultCharSet = a.GetCharSetValue (); switch (DefaultCharSet) { case CharSet.Ansi: