OSDN Git Service

gcc:
[pf3gnuchains/gcc-fork.git] / gcc / config / sh / symbian-cxx.c
1 /* Routines for C++ support for GCC for a Symbian OS targeted SH backend.
2    Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
3    Contributed by RedHat.
4    Most of this code is stolen from i386/winnt.c.
5
6    This file is part of GCC.
7
8    GCC is free software; you can redistribute it and/or modify it
9    under the terms of the GNU General Public License as published
10    by the Free Software Foundation; either version 3, or (at your
11    option) any later version.
12
13    GCC is distributed in the hope that it will be useful, but WITHOUT
14    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
16    License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with GCC; see the file COPYING3.  If not see
20    <http://www.gnu.org/licenses/>.  */
21
22 #include "config.h"
23 #include "system.h"
24 #include "coretypes.h"
25 #include "tm.h"
26 #include "rtl.h"
27 #include "output.h"
28 #include "flags.h"
29 #include "tree.h"
30 #include "expr.h"
31 #include "tm_p.h"
32 #include "cp/cp-tree.h" /* We need access to the OVL_... macros.  */
33 #include "toplev.h"
34 #include "sh-symbian.h"
35
36 \f
37 /* Return the type that we should use to determine if DECL is
38    imported or exported.  */
39
40 tree
41 sh_symbian_associated_type (tree decl)
42 {
43   tree t = NULL_TREE;
44
45   if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
46   /* Methods now inherit their dllimport/dllexport attributes correctly
47      so there is no need to check their class.  In fact it is wrong to
48      check their class since a method can remain unexported from an
49      exported class.  */
50     return t;
51
52   /* Otherwise we can just take the DECL_CONTEXT as normal.  */
53   if (DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl)))
54     t = DECL_CONTEXT (decl);
55
56   return t;
57 }
58
59 \f
60 /* Return nonzero if DECL is a dllimport'd object.  */
61
62 bool
63 sh_symbian_is_dllimported (tree decl)
64 {
65   tree imp;
66
67   if (   TREE_CODE (decl) != VAR_DECL
68       && TREE_CODE (decl) != FUNCTION_DECL)
69     return false;
70
71   imp = lookup_attribute ("dllimport", DECL_ATTRIBUTES (decl));
72   if (imp)
73     return true;
74
75   /* Class members get the dllimport status of their class.  */
76   imp = sh_symbian_associated_type (decl);
77   if (! imp)
78     return false;
79
80   imp = lookup_attribute ("dllimport", TYPE_ATTRIBUTES (imp));
81   if (!imp)
82     return false;
83
84   /* Don't mark defined functions as dllimport.  If the definition itself
85      was marked with dllimport, then sh_symbian_handle_dll_attribute reports
86      an error. This handles the case when the definition overrides an
87      earlier declaration.  */
88   if (TREE_CODE (decl) ==  FUNCTION_DECL
89       && DECL_INITIAL (decl)
90       && ! DECL_DECLARED_INLINE_P (decl))
91     {
92       /* Don't warn about artificial methods.  */
93       if (!DECL_ARTIFICIAL (decl))
94         warning (OPT_Wattributes, "function %q+D is defined after prior "
95                  "declaration as dllimport: attribute ignored",
96                  decl);
97       return false;
98     }
99
100   /* We ignore the dllimport attribute for inline member functions.
101      This differs from MSVC behavior which treats it like GNUC
102      'extern inline' extension.   */
103   else if (TREE_CODE (decl) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (decl))
104     {
105       if (extra_warnings)
106         warning (OPT_Wattributes, "inline function %q+D is declared as "
107                  "dllimport: attribute ignored",
108                  decl);
109       return false;
110     }
111
112   /*  Don't allow definitions of static data members in dllimport
113       class.  Just ignore the attribute for vtable data.  */
114   else if (TREE_CODE (decl) == VAR_DECL
115            && TREE_STATIC (decl)
116            && TREE_PUBLIC (decl)
117            && !DECL_EXTERNAL (decl))
118     {
119       if (!DECL_VIRTUAL_P (decl))
120         error ("definition of static data member %q+D of dllimport'd class",
121                decl);
122       return false;
123     }
124
125   /* Since we can't treat a pointer to a dllimport'd symbol as a
126      constant address, we turn off the attribute on C++ virtual
127      methods to allow creation of vtables using thunks.  Don't mark
128      artificial methods either (in sh_symbian_associated_type, only
129      COMDAT artificial method get import status from class context).  */
130   else if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE
131            && (DECL_VIRTUAL_P (decl) || DECL_ARTIFICIAL (decl)))
132     return false;
133
134   return true;
135 }
136
137 \f
138 /* This code implements a specification for exporting the vtable and rtti of
139    classes that have members with the dllexport or dllexport attributes.
140    This specification is defined here:
141
142      http://www.armdevzone.com/EABI/exported_class.txt
143
144    Basically it says that a class's vtable and rtti should be exported if
145    the following rules apply:
146
147    - If it has any non-inline non-pure virtual functions,
148      at least one of these need to be declared dllimport
149      OR any of the constructors is declared dllimport.
150
151    AND
152
153    - The class has an inline constructor/destructor and
154      a key-function (placement of vtable uniquely defined) that
155      is defined in this translation unit.
156
157    The specification also says that for classes which will have their
158    vtables and rtti exported that their base class(es) might also need a
159    similar exporting if:
160
161    - Every base class needs to have its vtable & rtti exported
162      as well, if the following the conditions hold true:
163      + The base class has a non-inline declared non-pure virtual function
164      + The base class is polymorphic (has or inherits any virtual functions)
165        or the base class has any virtual base classes.  */
166
167 /* Decide if a base class of a class should
168    also have its vtable and rtti exported.  */
169
170 static void
171 sh_symbian_possibly_export_base_class (tree base_class)
172 {
173   VEC(tree,gc) *method_vec;
174   int len;
175
176   if (! (TYPE_CONTAINS_VPTR_P (base_class)))
177     return;
178
179   method_vec = CLASSTYPE_METHOD_VEC (base_class);
180   len = method_vec ? VEC_length (tree, method_vec) : 0;
181
182   for (;len --;)
183     {
184       tree member = VEC_index (tree, method_vec, len);
185
186       if (! member)
187         continue;
188
189       for (member = OVL_CURRENT (member); member; member = OVL_NEXT (member))
190         {
191           if (TREE_CODE (member) != FUNCTION_DECL)
192             continue;
193
194           if (DECL_CONSTRUCTOR_P (member) || DECL_DESTRUCTOR_P (member))
195             continue;
196
197           if (! DECL_VIRTUAL_P (member))
198             continue;
199
200           if (DECL_PURE_VIRTUAL_P (member))
201             continue;
202
203           if (DECL_DECLARED_INLINE_P (member))
204             continue;
205
206           break;
207         }
208
209       if (member)
210         break;
211     }
212
213   if (len < 0)
214     return;
215
216   /* FIXME: According to the spec this base class should be exported, but
217      a) how do we do this ? and
218      b) it does not appear to be necessary for compliance with the Symbian
219         OS which so far is the only consumer of this code.  */
220 #if SYMBIAN_DEBUG
221   print_node_brief (stderr, "", base_class, 0);
222   fprintf (stderr, " EXPORTed [base class of exported class]\n");
223 #endif
224 }
225
226 /* Add the named attribute to the given node.  Copes with both DECLs and
227    TYPEs.  Will only add the attribute if it is not already present.  */
228
229 static void
230 sh_symbian_add_attribute (tree node, const char *attr_name)
231 {
232   tree attrs;
233   tree attr;
234
235   attrs = DECL_P (node) ? DECL_ATTRIBUTES (node) : TYPE_ATTRIBUTES (node);
236
237   if (lookup_attribute (attr_name, attrs) != NULL_TREE)
238     return;
239
240   attr = get_identifier (attr_name);
241
242   if (DECL_P (node))
243     DECL_ATTRIBUTES (node) = tree_cons (attr, NULL_TREE, attrs);
244   else
245     TYPE_ATTRIBUTES (node) = tree_cons (attr, NULL_TREE, attrs);
246
247 #if SYMBIAN_DEBUG
248   fprintf (stderr, "propagate %s attribute", attr_name);
249   print_node_brief (stderr, " to", node, 0);
250   fprintf (stderr, "\n");
251 #endif
252 }
253
254 /* Add the named attribute to a class and its vtable and rtti.  */
255
256 static void
257 sh_symbian_add_attribute_to_class_vtable_and_rtti (tree ctype, const char *attr_name)
258 {
259   sh_symbian_add_attribute (ctype, attr_name);
260
261   /* If the vtable exists then they need annotating as well.  */
262   if (CLASSTYPE_VTABLES (ctype))
263     /* XXX - Do we need to annotate any vtables other than the primary ?  */
264     sh_symbian_add_attribute (CLASSTYPE_VTABLES (ctype), attr_name);
265
266   /* If the rtti exists then it needs annotating as well.  */
267   if (TYPE_MAIN_VARIANT (ctype)
268       && CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (ctype)))
269     sh_symbian_add_attribute (CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (ctype)),
270                               attr_name);
271 }
272
273 /* Decide if a class needs to have an attribute because
274    one of its member functions has the attribute.  */
275
276 static bool
277 sh_symbian_class_needs_attribute (tree ctype, const char *attribute_name)
278 {
279   VEC(tree,gc) *method_vec;
280
281   method_vec = CLASSTYPE_METHOD_VEC (ctype);
282
283   /* If the key function has the attribute then the class needs it too.  */
284   if (TYPE_POLYMORPHIC_P (ctype)
285       && method_vec
286       && tree_contains_struct [TREE_CODE (ctype), TS_DECL_COMMON] == 1
287       && lookup_attribute (attribute_name,
288                            DECL_ATTRIBUTES (VEC_index (tree, method_vec, 0))))
289     return true;
290
291   /* Check the class's member functions.  */
292   if (TREE_CODE (ctype) == RECORD_TYPE)
293     {
294       unsigned int len;
295
296       len = method_vec ? VEC_length (tree, method_vec) : 0;
297
298       for (;len --;)
299         {
300           tree member = VEC_index (tree, method_vec, len);
301
302           if (! member)
303             continue;
304
305           for (member = OVL_CURRENT (member);
306                member;
307                member = OVL_NEXT (member))
308             {
309               if (TREE_CODE (member) != FUNCTION_DECL)
310                 continue;
311
312               if (DECL_PURE_VIRTUAL_P (member))
313                 continue;
314
315               if (! DECL_VIRTUAL_P (member))
316                 continue;
317
318               if (lookup_attribute (attribute_name, DECL_ATTRIBUTES (member)))
319                 {
320 #if SYMBIAN_DEBUG
321                   print_node_brief (stderr, "", ctype, 0);
322                   fprintf (stderr, " inherits %s because", attribute_name);
323                   print_node_brief (stderr, "", member, 0);
324                   fprintf (stderr, " has it.\n");
325 #endif
326                   return true;
327                 }
328             }
329         }
330     }
331
332 #if SYMBIAN_DEBUG
333   print_node_brief (stderr, "", ctype, 0);
334   fprintf (stderr, " does not inherit %s\n", attribute_name);
335 #endif
336   return false;
337 }
338
339 /* Decide if a class needs its vtable and rtti exporting.  */
340
341 static bool
342 symbian_export_vtable_and_rtti_p (tree ctype)
343 {
344   bool inline_ctor_dtor;
345   bool dllimport_ctor_dtor;
346   bool dllimport_member;
347   tree binfo, base_binfo;
348   VEC(tree,gc) *method_vec;
349   tree key;
350   int i;
351   int len;
352
353   /* Make sure that we are examining a class...  */
354   if (TREE_CODE (ctype) != RECORD_TYPE)
355     {
356 #if SYMBIAN_DEBUG
357       print_node_brief (stderr, "", ctype, 0);
358       fprintf (stderr, " does NOT need to be EXPORTed [not a class]\n");
359 #endif
360       return false;
361     }
362
363   /* If the class does not have a key function it
364      does not need to have its vtable exported.  */
365   if ((key = CLASSTYPE_KEY_METHOD (ctype)) == NULL_TREE)
366     {
367 #if SYMBIAN_DEBUG
368       print_node_brief (stderr, "", ctype, 0);
369       fprintf (stderr, " does NOT need to be EXPORTed [no key function]\n");
370 #endif
371       return false;
372     }
373
374   /* If the key fn has not been defined
375      then the class should not be exported.  */
376   if (! TREE_ASM_WRITTEN (key))
377     {
378 #if SYMBIAN_DEBUG
379       print_node_brief (stderr, "", ctype, 0);
380       fprintf (stderr, " does NOT need to be EXPORTed [key function not defined]\n");
381 #endif
382       return false;
383     }
384
385   /* Check the class's member functions.  */
386   inline_ctor_dtor = false;
387   dllimport_ctor_dtor = false;
388   dllimport_member = false;
389
390   method_vec = CLASSTYPE_METHOD_VEC (ctype);
391   len = method_vec ? VEC_length (tree, method_vec) : 0;
392
393   for (;len --;)
394     {
395       tree member = VEC_index (tree, method_vec, len);
396
397       if (! member)
398         continue;
399
400       for (member = OVL_CURRENT (member); member; member = OVL_NEXT (member))
401         {
402           if (TREE_CODE (member) != FUNCTION_DECL)
403             continue;
404
405           if (DECL_CONSTRUCTOR_P (member) || DECL_DESTRUCTOR_P (member))
406             {
407               if (DECL_DECLARED_INLINE_P (member)
408                   /* Ignore C++ backend created inline ctors/dtors.  */
409                   && (   DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (member)
410                       || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (member)))
411                 inline_ctor_dtor = true;
412
413               if (lookup_attribute ("dllimport", DECL_ATTRIBUTES (member)))
414                 dllimport_ctor_dtor = true;
415             }
416           else
417             {
418               if (DECL_PURE_VIRTUAL_P (member))
419                 continue;
420
421               if (! DECL_VIRTUAL_P (member))
422                 continue;
423
424               if (DECL_DECLARED_INLINE_P (member))
425                 continue;
426
427               if (lookup_attribute ("dllimport", DECL_ATTRIBUTES (member)))
428                 dllimport_member = true;
429             }
430         }
431     }
432
433   if (! dllimport_member && ! dllimport_ctor_dtor)
434     {
435 #if SYMBIAN_DEBUG
436       print_node_brief (stderr, "", ctype, 0);
437       fprintf (stderr,
438                " does NOT need to be EXPORTed [no non-pure virtuals or ctors/dtors with dllimport]\n");
439 #endif
440       return false;
441     }
442
443   if (! inline_ctor_dtor)
444     {
445 #if SYMBIAN_DEBUG
446       print_node_brief (stderr, "", ctype, 0);
447       fprintf (stderr,
448                " does NOT need to be EXPORTed [no inline ctor/dtor]\n");
449 #endif
450       return false;
451     }
452
453 #if SYMBIAN_DEBUG
454   print_node_brief (stderr, "", ctype, 0);
455   fprintf (stderr, " DOES need to be EXPORTed\n");
456 #endif
457
458   /* Now we must check and possibly export the base classes.  */
459   for (i = 0, binfo = TYPE_BINFO (ctype);
460        BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
461     sh_symbian_possibly_export_base_class (BINFO_TYPE (base_binfo));
462
463   return true;
464 }
465
466 /* Possibly override the decision to export class TYPE.  Upon entry
467    IMPORT_EXPORT will contain 1 if the class is going to be exported,
468    -1 if it is going to be imported and 0 otherwise.  This function
469    should return the modified value and perform any other actions
470    necessary to support the backend's targeted operating system.  */
471
472 int
473 sh_symbian_import_export_class (tree ctype, int import_export)
474 {
475   const char *attr_name = NULL;
476
477   /* If we are exporting the class but it does not have the dllexport
478      attribute then we may need to add it.  Similarly imported classes
479      may need the dllimport attribute.  */
480   switch (import_export)
481     {
482     case  1: attr_name = "dllexport"; break;
483     case -1: attr_name = "dllimport"; break;
484     default: break;
485     }
486
487   if (attr_name
488       && ! lookup_attribute (attr_name, TYPE_ATTRIBUTES (ctype)))
489     {
490       if (sh_symbian_class_needs_attribute (ctype, attr_name))
491         sh_symbian_add_attribute_to_class_vtable_and_rtti (ctype, attr_name);
492
493       /* Classes can be forced to export their
494          vtable and rtti under certain conditions.  */
495       if (symbian_export_vtable_and_rtti_p (ctype))
496         {
497           sh_symbian_add_attribute_to_class_vtable_and_rtti (ctype, "dllexport");
498
499           /* Make sure that the class and its vtable are exported.  */
500           import_export = 1;
501
502           if (CLASSTYPE_VTABLES (ctype))
503             DECL_EXTERNAL (CLASSTYPE_VTABLES (ctype)) = 1;
504
505           /* Check to make sure that if the class has a key method that
506              it is now on the list of keyed classes.  That way its vtable
507              will be emitted.  */
508           if (CLASSTYPE_KEY_METHOD (ctype))
509             {
510               tree class;
511
512               for (class = keyed_classes; class; class = TREE_CHAIN (class))
513                 if (class == ctype)
514                   break;
515
516               if (class == NULL_TREE)
517                 {
518 #if SYMBIAN_DEBUG
519                   print_node_brief (stderr, "Add node", ctype, 0);
520                   fprintf (stderr, " to the keyed classes list\n");
521 #endif
522                   keyed_classes = tree_cons (NULL_TREE, ctype, keyed_classes);
523                 }
524             }
525
526           /* Make sure that the typeinfo will be emitted as well.  */
527           if (CLASS_TYPE_P (ctype))
528             TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (ctype)))) = 1;
529         }
530     }
531
532   return import_export;
533 }
534
535 /* Handle a "dllimport" or "dllexport" attribute;
536    arguments as in struct attribute_spec.handler.  */
537
538 tree
539 sh_symbian_handle_dll_attribute (tree *pnode, tree name, tree args,
540                                  int flags, bool *no_add_attrs)
541 {
542   tree thunk;
543   tree node = *pnode;
544   const char *attr = IDENTIFIER_POINTER (name);
545
546   /* These attributes may apply to structure and union types being
547      created, but otherwise should pass to the declaration involved.  */
548   if (!DECL_P (node))
549     {
550       if (flags & ((int) ATTR_FLAG_DECL_NEXT
551                    | (int) ATTR_FLAG_FUNCTION_NEXT
552                    | (int) ATTR_FLAG_ARRAY_NEXT))
553         {
554           warning (OPT_Wattributes, "%qs attribute ignored", attr);
555           *no_add_attrs = true;
556           return tree_cons (name, args, NULL_TREE);
557         }
558
559       if (TREE_CODE (node) != RECORD_TYPE && TREE_CODE (node) != UNION_TYPE)
560         {
561           warning (OPT_Wattributes, "%qs attribute ignored", attr);
562           *no_add_attrs = true;
563         }
564
565       return NULL_TREE;
566     }
567
568   /* Report error on dllimport ambiguities
569      seen now before they cause any damage.  */
570   else if (is_attribute_p ("dllimport", name))
571     {
572       if (TREE_CODE (node) == VAR_DECL)
573         {
574           if (DECL_INITIAL (node))
575             {
576               error ("variable %q+D definition is marked dllimport",
577                      node);
578               *no_add_attrs = true;
579             }
580
581           /* `extern' needn't be specified with dllimport.
582              Specify `extern' now and hope for the best.  Sigh.  */
583           DECL_EXTERNAL (node) = 1;
584           /* Also, implicitly give dllimport'd variables declared within
585              a function global scope, unless declared static.  */
586           if (current_function_decl != NULL_TREE && ! TREE_STATIC (node))
587             TREE_PUBLIC (node) = 1;
588         }
589     }
590
591   /* If the node is an overloaded constructor or destructor, then we must
592      make sure that the attribute is propagated along the overload chain,
593      as it is these overloaded functions which will be emitted, rather than
594      the user declared constructor itself.  */
595   if (TREE_CODE (TREE_TYPE (node)) == METHOD_TYPE
596       && (DECL_CONSTRUCTOR_P (node) || DECL_DESTRUCTOR_P (node)))
597     {
598       tree overload;
599
600       for (overload = OVL_CHAIN (node); overload; overload = OVL_CHAIN (overload))
601         {
602           tree node_args;
603           tree func_args;
604           tree function = OVL_CURRENT (overload);
605
606           if (! function
607               || ! DECL_P (function)
608               || (DECL_CONSTRUCTOR_P (node) && ! DECL_CONSTRUCTOR_P (function))
609               || (DECL_DESTRUCTOR_P (node)  && ! DECL_DESTRUCTOR_P (function)))
610             continue;
611
612           /* The arguments must match as well.  */
613           for (node_args = DECL_ARGUMENTS (node), func_args = DECL_ARGUMENTS (function);
614                node_args && func_args;
615                node_args = TREE_CHAIN (node_args), func_args = TREE_CHAIN (func_args))
616             if (TREE_TYPE (node_args) != TREE_TYPE (func_args))
617               break;
618
619           if (node_args || func_args)
620             {
621               /* We can ignore an extraneous __in_chrg arguments in the node.
622                  GCC generated destructors, for example, will have this.  */
623               if ((node_args == NULL_TREE
624                    || func_args != NULL_TREE)
625                   && strcmp (IDENTIFIER_POINTER (DECL_NAME (node)), "__in_chrg") != 0)
626                 continue;
627             }
628
629           sh_symbian_add_attribute (function, attr);
630
631           /* Propagate the attribute to any function thunks as well.  */
632           for (thunk = DECL_THUNKS (function); thunk; thunk = TREE_CHAIN (thunk))
633             if (TREE_CODE (thunk) == FUNCTION_DECL)
634               sh_symbian_add_attribute (thunk, attr);
635         }
636     }
637
638   if (TREE_CODE (node) == FUNCTION_DECL && DECL_VIRTUAL_P (node))
639     {
640       /* Propagate the attribute to any thunks of this function.  */
641       for (thunk = DECL_THUNKS (node); thunk; thunk = TREE_CHAIN (thunk))
642         if (TREE_CODE (thunk) == FUNCTION_DECL)
643           sh_symbian_add_attribute (thunk, attr);
644     }
645
646   /*  Report error if symbol is not accessible at global scope.  */
647   if (!TREE_PUBLIC (node)
648       && (   TREE_CODE (node) == VAR_DECL
649           || TREE_CODE (node) == FUNCTION_DECL))
650     {
651       error ("external linkage required for symbol %q+D because of %qE attribute",
652              node, name);
653       *no_add_attrs = true;
654     }
655
656 #if SYMBIAN_DEBUG
657   print_node_brief (stderr, "mark node", node, 0);
658   fprintf (stderr, " as %s\n", attr);
659 #endif
660
661   return NULL_TREE;
662 }