2004-11-07 Ben Maurer <bmaurer@ximian.com>
[mono-project.git] / mcs / mbas / attribute.cs
blob5a21e2c3c106aec26987a6c7936887bc21e9e3a3
1 //
2 // attribute.cs: Attribute Handler
3 //
4 // Author: Ravi Pratap (ravi@ximian.com)
5 //
6 // Licensed under the terms of the GNU GPL
7 //
8 // (C) 2001 Ximian, Inc (http://www.ximian.com)
9 //
12 using System;
13 using System.Diagnostics;
14 using System.Collections;
15 using System.Reflection;
16 using System.Reflection.Emit;
17 using System.Runtime.InteropServices;
18 using System.Runtime.CompilerServices;
19 using System.Text;
21 namespace Mono.MonoBASIC {
23 /// <summary>
24 /// Base class for objects that can have Attributes applied to them.
25 /// </summary>
26 public abstract class Attributable {
27 /// <summary>
28 /// Attributes for this type
29 /// </summary>
30 Attributes attributes;
32 public Attributable(Attributes attrs)
34 attributes = attrs;
37 public Attributes OptAttributes
39 get {
40 return attributes;
42 set {
43 attributes = value;
47 public class Attribute {
48 public readonly string ExplicitTarget;
49 public readonly string Name;
50 public readonly ArrayList Arguments;
52 Location Location;
54 public Type Type;
56 // Is non-null if type is AttributeUsageAttribute
57 AttributeUsageAttribute usage_attribute;
59 public AttributeUsageAttribute UsageAttribute {
60 get {
61 return usage_attribute;
65 bool usage_attr = false;
67 MethodImplOptions ImplOptions;
68 UnmanagedType UnmanagedType;
69 CustomAttributeBuilder cb;
71 public Attribute (string name, ArrayList args, Location loc)
73 Name = name;
74 Arguments = args;
75 Location = loc;
78 public Attribute (string target, string name, ArrayList args, Location loc)
80 ExplicitTarget = target;
83 void Error_InvalidNamedArgument (string name)
85 Report.Error (617, Location, "'" + name + "' is not a valid named attribute " +
86 "argument. Named attribute arguments must be fields which are not " +
87 "readonly, static or const, or properties with a set accessor which "+
88 "are not static.");
91 void Error_AttributeArgumentNotValid ()
93 Report.Error (182, Location,
94 "An attribute argument must be a constant expression, typeof " +
95 "expression or array creation expression");
98 static void Error_AttributeConstructorMismatch (Location loc)
100 Report.Error (
101 -6, loc,
102 "Could not find a constructor for this argument list.");
105 private Type CheckAttributeType (EmitContext ec) {
106 Type t;
107 bool isattributeclass = true;
109 t = RootContext.LookupType (ec.DeclSpace, Name, true, Location);
110 if (t != null) {
111 isattributeclass = t.IsSubclassOf (TypeManager.attribute_type);
112 if (isattributeclass)
113 return t;
115 t = RootContext.LookupType (ec.DeclSpace, Name + "Attribute", true, Location);
116 if (t != null) {
117 if (t.IsSubclassOf (TypeManager.attribute_type))
118 return t;
120 if (!isattributeclass) {
121 Report.Error (616, Location, "'" + Name + "': is not an attribute class");
122 return null;
124 if (t != null) {
125 Report.Error (616, Location, "'" + Name + "Attribute': is not an attribute class");
126 return null;
128 Report.Error (
129 246, Location, "Could not find attribute '" + Name + "' (are you" +
130 " missing a using directive or an assembly reference ?)");
131 return null;
135 public Type ResolveType (EmitContext ec)
137 Type = CheckAttributeType (ec);
138 return Type;
142 public CustomAttributeBuilder Resolve (EmitContext ec)
144 if (Type == null)
145 Type = CheckAttributeType (ec);
146 if (Type == null)
147 return null;
149 bool MethodImplAttr = false;
150 bool MarshalAsAttr = false;
152 usage_attr = false;
154 if (Type == TypeManager.attribute_usage_type)
155 usage_attr = true;
156 if (Type == TypeManager.methodimpl_attr_type)
157 MethodImplAttr = true;
158 if (Type == TypeManager.marshal_as_attr_type)
159 MarshalAsAttr = true;
161 // Now we extract the positional and named arguments
163 ArrayList pos_args = new ArrayList ();
164 ArrayList named_args = new ArrayList ();
165 int pos_arg_count = 0;
167 if (Arguments != null) {
168 pos_args = (ArrayList) Arguments [0];
169 if (pos_args != null)
170 pos_arg_count = pos_args.Count;
171 if (Arguments.Count > 1)
172 named_args = (ArrayList) Arguments [1];
175 object [] pos_values = new object [pos_arg_count];
178 // First process positional arguments
181 int i;
182 for (i = 0; i < pos_arg_count; i++) {
183 Argument a = (Argument) pos_args [i];
184 Expression e;
186 if (!a.Resolve (ec, Location))
187 return null;
189 e = a.Expr;
191 if (e is Constant) {
192 pos_values [i] = ((Constant) e).GetValue ();
193 } else if (e is TypeOf) {
194 pos_values [i] = ((TypeOf) e).TypeArg;
195 } else {
196 Error_AttributeArgumentNotValid ();
197 return null;
200 if (usage_attr)
201 usage_attribute = new AttributeUsageAttribute ((AttributeTargets) pos_values [0]);
203 if (MethodImplAttr)
204 this.ImplOptions = (MethodImplOptions) pos_values [0];
206 if (MarshalAsAttr)
207 this.UnmanagedType =
208 (System.Runtime.InteropServices.UnmanagedType) pos_values [0];
212 // Now process named arguments
215 ArrayList field_infos = new ArrayList ();
216 ArrayList prop_infos = new ArrayList ();
217 ArrayList field_values = new ArrayList ();
218 ArrayList prop_values = new ArrayList ();
220 for (i = 0; i < named_args.Count; i++) {
221 DictionaryEntry de = (DictionaryEntry) named_args [i];
222 string member_name = (string) de.Key;
223 Argument a = (Argument) de.Value;
224 Expression e;
226 if (!a.Resolve (ec, Location))
227 return null;
229 Expression member = Expression.MemberLookup (
230 ec, Type, member_name,
231 MemberTypes.Field | MemberTypes.Property,
232 BindingFlags.Public | BindingFlags.Instance,
233 Location);
235 if (member == null || !(member is PropertyExpr || member is FieldExpr)) {
236 Error_InvalidNamedArgument (member_name);
237 return null;
240 e = a.Expr;
241 if (member is PropertyExpr) {
242 PropertyExpr pe = (PropertyExpr) member;
243 PropertyInfo pi = pe.PropertyInfo;
245 if (!pi.CanWrite) {
246 Error_InvalidNamedArgument (member_name);
247 return null;
250 if (e is Constant) {
251 object o = ((Constant) e).GetValue ();
252 prop_values.Add (o);
254 if (usage_attr) {
255 if (member_name == "AllowMultiple")
256 usage_attribute.AllowMultiple = (bool) o;
257 if (member_name == "Inherited")
258 usage_attribute.Inherited = (bool) o;
261 } else if (e is TypeOf) {
262 prop_values.Add (((TypeOf) e).TypeArg);
263 } else {
264 Error_AttributeArgumentNotValid ();
265 return null;
268 prop_infos.Add (pi);
270 } else if (member is FieldExpr) {
271 FieldExpr fe = (FieldExpr) member;
272 FieldInfo fi = fe.FieldInfo;
274 if (fi.IsInitOnly) {
275 Error_InvalidNamedArgument (member_name);
276 return null;
280 // Handle charset here, and set the TypeAttributes
282 if (e is Constant){
283 object value = ((Constant) e).GetValue ();
285 field_values.Add (value);
286 } else if (e is TypeOf) {
287 field_values.Add (((TypeOf) e).TypeArg);
288 } else {
289 Error_AttributeArgumentNotValid ();
290 return null;
293 field_infos.Add (fi);
297 Expression mg = Expression.MemberLookup (
298 ec, Type, ".ctor", MemberTypes.Constructor,
299 BindingFlags.Public | BindingFlags.Instance, Location);
301 if (mg == null) {
302 Error_AttributeConstructorMismatch (Location);
303 return null;
306 MethodBase constructor = Invocation.OverloadResolve (
307 ec, (MethodGroupExpr) mg, pos_args, Location);
309 if (constructor == null) {
310 Error_AttributeConstructorMismatch (Location);
311 return null;
315 // Now we perform some checks on the positional args as they
316 // cannot be null for a constructor which expects a parameter
317 // of type object
320 ParameterData pd = Invocation.GetParameterData (constructor);
322 for (int j = 0; j < pos_arg_count; ++j) {
323 Argument a = (Argument) pos_args [j];
325 if (a.Expr is NullLiteral && pd.ParameterType (j) == TypeManager.object_type) {
326 Error_AttributeArgumentNotValid ();
327 return null;
331 PropertyInfo [] prop_info_arr = new PropertyInfo [prop_infos.Count];
332 FieldInfo [] field_info_arr = new FieldInfo [field_infos.Count];
333 object [] field_values_arr = new object [field_values.Count];
334 object [] prop_values_arr = new object [prop_values.Count];
336 field_infos.CopyTo (field_info_arr, 0);
337 field_values.CopyTo (field_values_arr, 0);
339 prop_values.CopyTo (prop_values_arr, 0);
340 prop_infos.CopyTo (prop_info_arr, 0);
342 try {
343 cb = new CustomAttributeBuilder (
344 (ConstructorInfo) constructor, pos_values,
345 prop_info_arr, prop_values_arr,
346 field_info_arr, field_values_arr);
348 } catch (NullReferenceException) {
350 // Don't know what to do here
352 } catch {
354 // Sample:
355 // using System.ComponentModel;
356 // [DefaultValue (CollectionChangeAction.Add)]
357 // class X { static void Main () {} }
359 Report.Warning (
360 -23, Location,
361 "The compiler can not encode this attribute in .NET due to\n" +
362 "\ta bug in the .NET runtime. Try the Mono runtime");
365 return cb;
368 static string GetValidPlaces (Attribute attr)
370 StringBuilder sb = new StringBuilder ();
371 AttributeTargets targets = attr.GetAttributeUsage ().ValidOn;
373 if ((targets & AttributeTargets.Assembly) != 0)
374 sb.Append ("'assembly' ");
376 if ((targets & AttributeTargets.Class) != 0)
377 sb.Append ("'class' ");
379 if ((targets & AttributeTargets.Constructor) != 0)
380 sb.Append ("'constructor' ");
382 if ((targets & AttributeTargets.Delegate) != 0)
383 sb.Append ("'delegate' ");
385 if ((targets & AttributeTargets.Enum) != 0)
386 sb.Append ("'enum' ");
388 if ((targets & AttributeTargets.Event) != 0)
389 sb.Append ("'event' ");
391 if ((targets & AttributeTargets.Field) != 0)
392 sb.Append ("'field' ");
394 if ((targets & AttributeTargets.Interface) != 0)
395 sb.Append ("'interface' ");
397 if ((targets & AttributeTargets.Method) != 0)
398 sb.Append ("'method' ");
400 if ((targets & AttributeTargets.Module) != 0)
401 sb.Append ("'module' ");
403 if ((targets & AttributeTargets.Parameter) != 0)
404 sb.Append ("'parameter' ");
406 if ((targets & AttributeTargets.Property) != 0)
407 sb.Append ("'property' ");
409 if ((targets & AttributeTargets.ReturnValue) != 0)
410 sb.Append ("'return value' ");
412 if ((targets & AttributeTargets.Struct) != 0)
413 sb.Append ("'struct' ");
415 return sb.ToString ();
419 public static void Error_AttributeNotValidForElement (Attribute a, Location loc)
421 Report.Error (
422 592, loc, "Attribute '" + a.Name +
423 "' is not valid on this declaration type. " +
424 "It is valid on " + GetValidPlaces (a) + "declarations only.");
427 public static bool CheckAttribute (Attribute a, object element)
429 TypeContainer attr = TypeManager.LookupClass (a.Type);
430 AttributeTargets targets = a.GetAttributeUsage ().ValidOn;
432 if (element is Class) {
433 if ((targets & AttributeTargets.Class) != 0)
434 return true;
435 else
436 return false;
438 } else if (element is Struct) {
439 if ((targets & AttributeTargets.Struct) != 0)
440 return true;
441 else
442 return false;
443 } else if (element is Constructor) {
444 if ((targets & AttributeTargets.Constructor) != 0)
445 return true;
446 else
447 return false;
448 } else if (element is Delegate) {
449 if ((targets & AttributeTargets.Delegate) != 0)
450 return true;
451 else
452 return false;
453 } else if (element is Enum) {
454 if ((targets & AttributeTargets.Enum) != 0)
455 return true;
456 else
457 return false;
458 } else if (element is Event /*|| element is InterfaceEvent*/) {
459 if ((targets & AttributeTargets.Event) != 0)
460 return true;
461 else
462 return false;
463 } else if (element is Field || element is FieldBuilder) {
464 if ((targets & AttributeTargets.Field) != 0)
465 return true;
466 else
467 return false;
468 } else if (element is Interface) {
469 if ((targets & AttributeTargets.Interface) != 0)
470 return true;
471 else
472 return false;
473 } else if (element is Method || element is Accessor) {
474 if ((targets & AttributeTargets.Method) != 0)
475 return true;
476 else
477 return false;
478 } else if (element is ParameterBuilder) {
479 if ((targets & AttributeTargets.Parameter) != 0)
480 return true;
481 else
482 return false;
483 } else if (element is Property || element is Indexer /*||
484 element is InterfaceProperty || element is InterfaceIndexer*/) {
485 if ((targets & AttributeTargets.Property) != 0)
486 return true;
487 else
488 return false;
489 } else if (element is AssemblyBuilder){
490 if ((targets & AttributeTargets.Assembly) != 0)
491 return true;
492 else
493 return false;
494 } else if (element is ModuleBuilder){
495 if ((targets & AttributeTargets.Module) != 0)
496 return true;
497 else
498 return false;
501 return false;
504 /// <summary>
505 /// Returns AttributeUsage attribute for this type
506 /// </summary>
507 public AttributeUsageAttribute GetAttributeUsage ()
509 Class attr_class = (Class) TypeManager.LookupClass (Type);
511 if (attr_class == null) {
512 object[] usage_attr = Type.GetCustomAttributes (TypeManager.attribute_usage_type, true);
513 return (AttributeUsageAttribute)usage_attr [0];
516 return attr_class.AttributeUsage;
520 // This method should be invoked to pull the IndexerName attribute from an
521 // Indexer if it exists.
523 public static string ScanForIndexerName (EmitContext ec, Attributes opt_attrs)
525 if (opt_attrs == null)
526 return null;
528 foreach (Attribute a in opt_attrs.Attrs) {
529 if (a.ResolveType (ec) == null)
530 return null;
532 if (a.Type != TypeManager.indexer_name_type)
533 continue;
536 // So we have found an IndexerName, pull the data out.
538 if (a.Arguments == null || a.Arguments [0] == null){
539 Error_AttributeConstructorMismatch (a.Location);
540 return null;
542 ArrayList pos_args = (ArrayList) a.Arguments [0];
543 if (pos_args.Count == 0){
544 Error_AttributeConstructorMismatch (a.Location);
545 return null;
548 Argument arg = (Argument) pos_args [0];
549 if (!arg.Resolve (ec, a.Location))
550 return null;
552 Expression e = arg.Expr;
553 if (!(e is StringConstant)){
554 Error_AttributeConstructorMismatch (a.Location);
555 return null;
559 // Remove the attribute from the list
561 opt_attrs.Attrs.Remove (a);
563 return (((StringConstant) e).Value);
565 return null;
569 // This pulls the condition name out of a Conditional attribute
571 public string Conditional_GetConditionName ()
574 // So we have a Conditional, pull the data out.
576 if (Arguments == null || Arguments [0] == null){
577 Error_AttributeConstructorMismatch (Location);
578 return null;
581 ArrayList pos_args = (ArrayList) Arguments [0];
582 if (pos_args.Count != 1){
583 Error_AttributeConstructorMismatch (Location);
584 return null;
587 Argument arg = (Argument) pos_args [0];
588 if (!(arg.Expr is StringConstant)){
589 Error_AttributeConstructorMismatch (Location);
590 return null;
593 return ((StringConstant) arg.Expr).Value;
597 // This pulls the obsolete message and error flag out of an Obsolete attribute
599 public string Obsolete_GetObsoleteMessage (out bool is_error)
601 is_error = false;
603 // So we have an Obsolete, pull the data out.
605 if (Arguments == null || Arguments [0] == null)
606 return "";
608 ArrayList pos_args = (ArrayList) Arguments [0];
609 if (pos_args.Count == 0)
610 return "";
611 else if (pos_args.Count > 2){
612 Error_AttributeConstructorMismatch (Location);
613 return null;
616 Argument arg = (Argument) pos_args [0];
617 if (!(arg.Expr is StringConstant)){
618 Error_AttributeConstructorMismatch (Location);
619 return null;
622 if (pos_args.Count == 2){
623 Argument arg2 = (Argument) pos_args [1];
624 if (!(arg2.Expr is BoolConstant)){
625 Error_AttributeConstructorMismatch (Location);
626 return null;
628 is_error = ((BoolConstant) arg2.Expr).Value;
631 return ((StringConstant) arg.Expr).Value;
635 // Applies the attributes to the `builder'.
637 public static void ApplyAttributes (EmitContext ec, object builder, object kind,
638 Attributes opt_attrs, Location loc)
640 if (opt_attrs == null)
641 return;
643 foreach (Attribute a in opt_attrs.Attrs) {
644 CustomAttributeBuilder cb = a.Resolve (ec);
646 if (cb == null)
647 continue;
649 if (!(kind is TypeContainer))
650 if (!CheckAttribute (a, kind)) {
651 Error_AttributeNotValidForElement (a, loc);
652 return;
655 if (kind is Method || kind is Accessor) {
656 if (a.Type == TypeManager.methodimpl_attr_type) {
657 if (a.ImplOptions == MethodImplOptions.InternalCall)
658 ((MethodBuilder) builder).SetImplementationFlags (MethodImplAttributes.InternalCall | MethodImplAttributes.Runtime);
659 } else if (a.Type != TypeManager.dllimport_type){
660 ((MethodBuilder) builder).SetCustomAttribute (cb);
662 } else if (kind is Constructor) {
663 ((ConstructorBuilder) builder).SetCustomAttribute (cb);
664 } else if (kind is Field) {
665 ((FieldBuilder) builder).SetCustomAttribute (cb);
666 } else if (kind is Property || kind is Indexer) {
667 ((PropertyBuilder) builder).SetCustomAttribute (cb);
668 } else if (kind is Event) {
669 ((MyEventBuilder) builder).SetCustomAttribute (cb);
670 } else if (kind is ParameterBuilder) {
671 if (a.Type == TypeManager.marshal_as_attr_type) {
672 UnmanagedMarshal marshal = UnmanagedMarshal.DefineUnmanagedMarshal (a.UnmanagedType);
673 ((ParameterBuilder) builder).SetMarshal (marshal);
674 } else
675 ((ParameterBuilder) builder).SetCustomAttribute (cb);
676 } else if (kind is Enum) {
677 ((TypeBuilder) builder).SetCustomAttribute (cb);
678 } else if (kind is TypeContainer) {
679 TypeContainer tc = (TypeContainer) kind;
681 if (a.UsageAttribute != null) {
682 tc.AttributeUsage = a.UsageAttribute;
683 } else if (a.Type == TypeManager.default_member_type) {
684 if (tc.Indexers != null) {
685 Report.Error (646, loc, "Cannot specify the DefaultMember attribute on" + " a type containing an indexer");
686 return;
688 } else {
689 if (!CheckAttribute (a, kind)) {
690 Error_AttributeNotValidForElement (a, loc);
691 return;
695 try {
696 ((TypeBuilder) builder).SetCustomAttribute (cb);
697 } catch (System.ArgumentException) {
698 Report.Warning (-21, loc, "The CharSet named property on StructLayout\n"+"\tdoes not work correctly on Microsoft.NET\n"+"\tYou might want to remove the CharSet declaration\n"+"\tor compile using the Mono runtime instead of the\n"+"\tMicrosoft .NET runtime");
700 } else if (kind is Interface) {
701 Interface iface = (Interface) kind;
702 if (!CheckAttribute (a, kind)) {
703 Error_AttributeNotValidForElement (a, loc);
704 return;
706 ((TypeBuilder) builder).SetCustomAttribute (cb);
707 } else if (kind is AssemblyBuilder){
708 ((AssemblyBuilder) builder).SetCustomAttribute (cb);
709 } else if (kind is ModuleBuilder) {
710 ((ModuleBuilder) builder).SetCustomAttribute (cb);
711 } else if (kind is FieldBuilder) {
712 ((FieldBuilder) builder).SetCustomAttribute (cb);
713 } else
714 throw new Exception ("Unknown kind: " + kind);
718 public MethodBuilder DefinePInvokeMethod (EmitContext ec, TypeBuilder builder, string name,
719 MethodAttributes flags, Type ret_type, Type [] param_types)
722 // We extract from the attribute the information we need
725 if (Arguments == null) {
726 Console.WriteLine ("Internal error : this is not supposed to happen !");
727 return null;
730 Type = CheckAttributeType (ec);
731 if (Type == null)
732 return null;
734 ArrayList named_args = new ArrayList ();
736 ArrayList pos_args = (ArrayList) Arguments [0];
737 if (Arguments.Count > 1)
738 named_args = (ArrayList) Arguments [1];
741 string dll_name = null;
743 Argument tmp = (Argument) pos_args [0];
745 if (!tmp.Resolve (ec, Location))
746 return null;
748 if (tmp.Expr is Constant)
749 dll_name = (string) ((Constant) tmp.Expr).GetValue ();
750 else {
751 Error_AttributeArgumentNotValid ();
752 return null;
755 // Now we process the named arguments
756 CallingConvention cc = CallingConvention.Winapi;
757 CharSet charset = CharSet.Ansi;
758 bool preserve_sig = true;
759 bool exact_spelling = false;
760 bool set_last_err = false;
761 string entry_point = null;
763 for (int i = 0; i < named_args.Count; i++) {
765 DictionaryEntry de = (DictionaryEntry) named_args [i];
767 string member_name = (string) de.Key;
768 Argument a = (Argument) de.Value;
770 if (!a.Resolve (ec, Location))
771 return null;
773 Expression member = Expression.MemberLookup (
774 ec, Type, member_name,
775 MemberTypes.Field | MemberTypes.Property,
776 BindingFlags.Public | BindingFlags.Instance,
777 Location);
779 if (member == null || !(member is FieldExpr)) {
780 Error_InvalidNamedArgument (member_name);
781 return null;
784 if (member is FieldExpr) {
785 FieldExpr fe = (FieldExpr) member;
786 FieldInfo fi = fe.FieldInfo;
788 if (fi.IsInitOnly) {
789 Error_InvalidNamedArgument (member_name);
790 return null;
793 if (a.Expr is Constant) {
794 Constant c = (Constant) a.Expr;
796 if (member_name == "CallingConvention")
797 cc = (CallingConvention) c.GetValue ();
798 else if (member_name == "CharSet")
799 charset = (CharSet) c.GetValue ();
800 else if (member_name == "EntryPoint")
801 entry_point = (string) c.GetValue ();
802 else if (member_name == "SetLastError")
803 set_last_err = (bool) c.GetValue ();
804 else if (member_name == "ExactSpelling")
805 exact_spelling = (bool) c.GetValue ();
806 else if (member_name == "PreserveSig")
807 preserve_sig = (bool) c.GetValue ();
808 } else {
809 Error_AttributeArgumentNotValid ();
810 return null;
816 if (entry_point == null)
817 entry_point = name;
819 MethodBuilder mb = builder.DefinePInvokeMethod (
820 name, dll_name, entry_point, flags | MethodAttributes.HideBySig,
821 CallingConventions.Standard,
822 ret_type,
823 param_types,
825 charset);
827 if (preserve_sig)
828 mb.SetImplementationFlags (MethodImplAttributes.PreserveSig);
830 return mb;
833 public bool IsAssemblyAttribute {
834 get {
835 return ExplicitTarget == "assembly";
839 public bool IsModuleAttribute {
840 get {
841 return ExplicitTarget == "module";
846 public class Attributes {
847 public ArrayList Attrs;
848 public Location Location;
850 public Attributes (Attribute a)
852 Attrs = new ArrayList ();
853 Attrs.Add (a);
856 public Attributes (ArrayList attrs)
858 Attrs = attrs;
861 public void Add (Attribute attr)
863 Attrs.Add (attr);
866 public void Add (ArrayList attrs)
868 Attrs.AddRange (attrs);
871 // public void Emit (EmitContext ec, Attributable ias)
872 // {
873 // ListDictionary ld = new ListDictionary ();
875 // foreach (Attribute a in Attrs)
876 // a.Emit (ec, ias, ld);
877 // }