**** Merged from MCS ****
[mono.git] / mcs / gmcs / codegen.cs
index a67804ce5097a9ec1212cc7e6e7d30005166fcef..5e1113b035e41e9a509be6e60b11070a6feb251e 100755 (executable)
@@ -12,6 +12,7 @@ using System.IO;
 using System.Collections;
 using System.Reflection;
 using System.Reflection.Emit;
+using System.Runtime.InteropServices;
 using System.Security.Cryptography;
 
 using Mono.Security.Cryptography;
@@ -138,7 +139,17 @@ namespace Mono.CSharp {
                {
                        try {
                                Assembly.Builder.Save (Basename (name));
-                       } catch (System.IO.IOException io){
+                       }
+                       catch (COMException) {
+                               if ((RootContext.StrongNameKeyFile == null) || (!RootContext.StrongNameDelaySign))
+                                       throw;
+
+                               // FIXME: it seems Microsoft AssemblyBuilder doesn't like to delay sign assemblies 
+                               Report.Error (1548, "Couldn't delay-sign the assembly with the '" +
+                                       RootContext.StrongNameKeyFile +
+                                       "', Use MCS with the Mono runtime or CSC to compile this assembly.");
+                       }
+                       catch (System.IO.IOException io) {
                                Report.Error (16, "Could not write to file `"+name+"', cause: " + io.Message);
                        }
                }
@@ -724,14 +735,17 @@ namespace Mono.CSharp {
                //
                public void EmitThis ()
                {
-                       ig.Emit (OpCodes.Ldarg_0);
-
-                       if (!IsStatic){
-                               if (InIterator)
-                                       ig.Emit (OpCodes.Ldfld, IteratorHandler.Current.this_field);
-                               else
-                                       throw new Exception ("EmitThis for an unknown state");
-                       }
+                       if (InIterator){
+                               ig.Emit (OpCodes.Ldarg_0);
+                               if (!IsStatic){
+                                       FieldBuilder this_field = IteratorHandler.Current.this_field;
+                                       if (TypeManager.IsValueType (this_field.FieldType))
+                                               ig.Emit (OpCodes.Ldflda, this_field);
+                                       else
+                                               ig.Emit (OpCodes.Ldfld, this_field);
+                               } 
+                       } else
+                               ig.Emit (OpCodes.Ldarg_0);
                }
 
                public Expression GetThis (Location loc)
@@ -750,81 +764,54 @@ namespace Mono.CSharp {
        }
 
 
-       public abstract class CommonAssemblyModulClass: IAttributeSupport {
-               protected Hashtable m_attributes;
+       public abstract class CommonAssemblyModulClass: Attributable {
+               static string[] attribute_targets = new string [] { "assembly", "module" };
 
-               protected CommonAssemblyModulClass () 
+               protected CommonAssemblyModulClass ():
+                       base (null)
                {
-                       m_attributes = new Hashtable ();
                }
 
-               //
-               // Adds a global attribute that was declared in `container', 
-               // the attribute is in `attr', and it was defined at `loc'
-               //                
-               public void AddAttribute (TypeContainer container, AttributeSection attr)
+               // TODO: The error can be reported more than once
+               public void AddAttributes (ArrayList attrs)
                {
-                       NamespaceEntry ns = container.NamespaceEntry;
-                       Attributes a = (Attributes) m_attributes [ns];
-
-                       if (a == null) {
-                               m_attributes [ns] = new Attributes (attr);
+                       if (OptAttributes == null) {
+                               OptAttributes = new Attributes (attrs);
+                               OptAttributes.CheckTargets (ValidAttributeTargets);
                                return;
                        }
-
-                       a.AddAttributeSection (attr);
+                       OptAttributes.AddAttributes (attrs);
+                       OptAttributes.CheckTargets (ValidAttributeTargets);
                }
 
-               public virtual void Emit () 
+               public virtual void Emit (TypeContainer tc
                {
-                       if (m_attributes.Count < 1)
+                       if (OptAttributes == null)
                                return;
 
-                       TypeContainer dummy = new TypeContainer ();
-                       EmitContext temp_ec = new EmitContext (dummy, Mono.CSharp.Location.Null, null, null, 0, false);
-                       
-                       foreach (DictionaryEntry de in m_attributes)
-                       {
-                               NamespaceEntry ns = (NamespaceEntry) de.Key;
-                               Attributes attrs = (Attributes) de.Value;
-                               
-                               dummy.NamespaceEntry = ns;
-                               Attribute.ApplyAttributes (temp_ec, null, this, attrs);
-                       }
+                       EmitContext ec = new EmitContext (tc, Mono.CSharp.Location.Null, null, null, 0, false);
+                       OptAttributes.Emit (ec, this);
                }
-                
+
                protected Attribute GetClsCompliantAttribute ()
                {
-                       if (m_attributes.Count < 1)
+                       if (OptAttributes == null)
                                return null;
 
                        EmitContext temp_ec = new EmitContext (new TypeContainer (), Mono.CSharp.Location.Null, null, null, 0, false);
-                       
-                       foreach (DictionaryEntry de in m_attributes) {
-
-                               NamespaceEntry ns = (NamespaceEntry) de.Key;
-                               Attributes attrs = (Attributes) de.Value;
-                               temp_ec.TypeContainer.NamespaceEntry = ns;
-
-                               foreach (AttributeSection attr_section in attrs.AttributeSections) {
-                                       foreach (Attribute a in attr_section.Attributes) {
-                                               TypeExpr attributeType = RootContext.LookupType (temp_ec.DeclSpace, Attributes.GetAttributeFullName (a.Name), true, Location.Null);
-                                               if (attributeType.Type == TypeManager.cls_compliant_attribute_type) {
-                                                       a.Resolve (temp_ec);
-                                                       return a;
-                                               }
-                                       }
-                               }
+                       Attribute a = OptAttributes.Search (TypeManager.cls_compliant_attribute_type, temp_ec);
+                       if (a != null) {
+                               a.Resolve (temp_ec);
                        }
-                       return null;
+                       return a;
                }
-                
-               #region IAttributeSupport Members
-               public abstract void SetCustomAttribute(CustomAttributeBuilder customBuilder);
-               #endregion
 
+               protected override string[] ValidAttributeTargets {
+                       get {
+                               return attribute_targets;
+                       }
+               }
        }
-       
 
        public class AssemblyClass: CommonAssemblyModulClass {
                // TODO: make it private and move all builder based methods here
@@ -843,6 +830,17 @@ namespace Mono.CSharp {
                        }
                        }
 
+               public override AttributeTargets AttributeTargets {
+                       get {
+                               return AttributeTargets.Assembly;
+                       }
+               }
+
+               public override bool IsClsCompliaceRequired(DeclSpace ds)
+               {
+                       return is_cls_compliant;
+               }
+
                public void ResolveClsCompliance ()
                {
                        Attribute a = GetClsCompliantAttribute ();
@@ -854,17 +852,17 @@ namespace Mono.CSharp {
 
                public AssemblyName GetAssemblyName (string name, string output) 
                {
-                       // scan assembly attributes for strongname related attr
-                       foreach (DictionaryEntry nsattr in m_attributes) {
-                               ArrayList list = ((Attributes)nsattr.Value).AttributeSections;
-                               for (int i=0; i < list.Count; i++) {
-                                       AttributeSection asect = (AttributeSection) list [i];
-                                       if (asect.Target != "assembly")
+                       if (OptAttributes != null) {
+                               foreach (Attribute a in OptAttributes.Attrs) {
+                                       if (a.Target != "assembly")
                                                continue;
-                                       // strongname attributes don't support AllowMultiple
-                                       Attribute a = (Attribute) asect.Attributes [0];
+                                       // TODO: This code is buggy: comparing Attribute name without resolving it is wrong.
+                                       //       However, this is invoked by CodeGen.Init, at which time none of the namespaces
+                                       //       are loaded yet.
                                        switch (a.Name) {
                                                case "AssemblyKeyFile":
+                                               case "AssemblyKeyFileAttribute":
+                                               case "System.Reflection.AssemblyKeyFileAttribute":
                                                        if (RootContext.StrongNameKeyFile != null) {
                                                                Report.Warning (1616, "Compiler option -keyfile overrides " +
                                                                        "AssemblyKeyFileAttribute");
@@ -876,6 +874,8 @@ namespace Mono.CSharp {
                                                        }
                                                        break;
                                                case "AssemblyKeyName":
+                                               case "AssemblyKeyNameAttribute":
+                                               case "System.Reflection.AssemblyKeyNameAttribute":
                                                        if (RootContext.StrongNameKeyContainer != null) {
                                                                Report.Warning (1616, "Compiler option -keycontainer overrides " +
                                                                        "AssemblyKeyNameAttribute");
@@ -887,6 +887,8 @@ namespace Mono.CSharp {
                                                        }
                                                        break;
                                                case "AssemblyDelaySign":
+                                               case "AssemblyDelaySignAttribute":
+                                               case "System.Reflection.AssemblyDelaySignAttribute":
                                                        RootContext.StrongNameDelaySign = a.GetBoolean ();
                                                        break;
                                        }
@@ -922,21 +924,51 @@ namespace Mono.CSharp {
                        }
 
                        if (exist) {
-                               using (FileStream fs = new FileStream (filename, FileMode.Open)) {
+                               using (FileStream fs = new FileStream (filename, FileMode.Open, FileAccess.Read)) {
                                        byte[] snkeypair = new byte [fs.Length];
                                        fs.Read (snkeypair, 0, snkeypair.Length);
 
-                                       try {
-                                               // this will import public or private/public keys
-                                               RSA rsa = CryptoConvert.FromCapiKeyBlob (snkeypair);
-                                               // only the public part must be supplied if signature is delayed
-                                               byte[] key = CryptoConvert.ToCapiKeyBlob (rsa, !RootContext.StrongNameDelaySign);
-                                               an.KeyPair = new StrongNameKeyPair (key);
+                                       if (RootContext.StrongNameDelaySign) {
+                                               // delayed signing - DO NOT include private key
+                                               try {
+                                                       // check for possible ECMA key
+                                                       if (snkeypair.Length == 16) {
+                                                               // will be rejected if not "the" ECMA key
+                                                               an.KeyPair = new StrongNameKeyPair (snkeypair);
+                                                       }
+                                                       else {
+                                                               // take it, with or without, a private key
+                                                               RSA rsa = CryptoConvert.FromCapiKeyBlob (snkeypair);
+                                                               // and make sure we only feed the public part to Sys.Ref
+                                                               byte[] publickey = CryptoConvert.ToCapiPublicKeyBlob (rsa);
+                                                               an.KeyPair = new StrongNameKeyPair (publickey);
+                                                       }
+                                               }
+                                               catch (Exception) {
+                                                       Report.Error (1548, "Could not strongname the assembly. File `" +
+                                                               RootContext.StrongNameKeyFile + "' incorrectly encoded.");
+                                                       Environment.Exit (1);
+                                               }
                                        }
-                                       catch (CryptographicException) {
-                                               Report.Error (1548, "Could not strongname the assembly. File `" +
-                                                       RootContext.StrongNameKeyFile + "' incorrectly encoded.");
-                                               Environment.Exit (1);
+                                       else {
+                                               // no delay so we make sure we have the private key
+                                               try {
+                                                       CryptoConvert.FromCapiPrivateKeyBlob (snkeypair);
+                                                       an.KeyPair = new StrongNameKeyPair (snkeypair);
+                                               }
+                                               catch (CryptographicException) {
+                                                       if (snkeypair.Length == 16) {
+                                                               // error # is different for ECMA key
+                                                               Report.Error (1606, "Could not strongname the assembly. " + 
+                                                                       "ECMA key can only be used to delay-sign assemblies");
+                                                       }
+                                                       else {
+                                                               Report.Error (1548, "Could not strongname the assembly. File `" +
+                                                                       RootContext.StrongNameKeyFile +
+                                                                       "' doesn't have a private key.");
+                                                       }
+                                                       Environment.Exit (1);
+                                               }
                                        }
                                }
                        }
@@ -948,7 +980,7 @@ namespace Mono.CSharp {
                        return an;
                }
 
-               public override void SetCustomAttribute(CustomAttributeBuilder customBuilder)
+               public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder customBuilder)
                {
                        Builder.SetCustomAttribute (customBuilder);
                }
@@ -957,7 +989,6 @@ namespace Mono.CSharp {
        public class ModuleClass: CommonAssemblyModulClass {
                // TODO: make it private and move all builder based methods here
                public ModuleBuilder Builder;
-            
                bool m_module_is_unsafe;
 
                public ModuleClass (bool is_unsafe)
@@ -965,15 +996,21 @@ namespace Mono.CSharp {
                        m_module_is_unsafe = is_unsafe;
                }
 
-               public override void Emit () 
-               {
-                       base.Emit ();
+               public override AttributeTargets AttributeTargets {
+                       get {
+                               return AttributeTargets.Module;
+                       }
+               }
 
-                       Attribute a = GetClsCompliantAttribute ();
-                       if (a != null) {
-                               Report.Warning (3012, a.Location);
+               public override bool IsClsCompliaceRequired(DeclSpace ds)
+               {
+                       return CodeGen.Assembly.IsClsCompliant;
                        }
 
+               public override void Emit (TypeContainer tc) 
+               {
+                       base.Emit (tc);
+
                        if (!m_module_is_unsafe)
                                return;
 
@@ -982,11 +1019,16 @@ namespace Mono.CSharp {
                                return;
                        }
                                
-                       SetCustomAttribute (new CustomAttributeBuilder (TypeManager.unverifiable_code_ctor, new object [0]));
+                       ApplyAttributeBuilder (null, new CustomAttributeBuilder (TypeManager.unverifiable_code_ctor, new object [0]));
                }
                 
-               public override void SetCustomAttribute(CustomAttributeBuilder customBuilder)
+               public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder customBuilder)
                {
+                       if (a != null && a.Type == TypeManager.cls_compliant_attribute_type) {
+                               Report.Warning_T (3012, a.Location);
+                               return;
+                       }
+
                        Builder.SetCustomAttribute (customBuilder);
                }
        }