OSDN Git Service

* common.opt (-Wattributes): New. Default true.
[pf3gnuchains/gcc-fork.git] / gcc / config / sh / symbian.c
1 /* Routines for GCC for a Symbian OS targeted SH backend.
2    Copyright (C) 2004, 2005 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 2, 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 COPYING.  If not, write to
20    the Free Software Foundation, 59 Temple Place - Suite 330,
21    Boston, MA 02111-1307, USA.  */
22
23 #include "config.h"
24 #include "system.h"
25 #include "coretypes.h"
26 #include "tm.h"
27 #include "rtl.h"
28 #include "output.h"
29 #include "flags.h"
30 #include "tree.h"
31 #include "expr.h"
32 #include "tm_p.h"
33 #include "cp/cp-tree.h" /* We need access to the OVL_... macros.  */
34 #include "toplev.h"
35
36 /* Select the level of debugging information to display.
37    0 for no debugging.
38    1 for informative messages about decisions to add attributes
39    2 for verbose information about what is being done.  */
40 #define SYMBIAN_DEBUG 0
41 //#define SYMBIAN_DEBUG 1
42 //#define SYMBIAN_DEBUG 2
43
44 /* A unique character to encode declspec encoded objects.  */
45 #define SH_SYMBIAN_FLAG_CHAR "$"
46
47 /* Unique strings to prefix exported and imported objects.  */
48 #define DLL_IMPORT_PREFIX SH_SYMBIAN_FLAG_CHAR "i."
49 #define DLL_EXPORT_PREFIX SH_SYMBIAN_FLAG_CHAR "e."
50
51 \f
52 /* Return the type that we should use to determine if DECL is
53    imported or exported.  */
54
55 static tree
56 sh_symbian_associated_type (tree decl)
57 {
58   tree t = NULL_TREE;
59
60   if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
61   /* Methods now inherit their dllimport/dllexport attributes correctly
62      so there is no need to check their class.  In fact it is wrong to
63      check their class since a method can remain unexported from an
64      exported class.  */
65     return t;
66
67   /* Otherwise we can just take the DECL_CONTEXT as normal.  */
68   if (DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl)))
69     t = DECL_CONTEXT (decl);
70
71   return t;
72 }
73
74 /* Return nonzero if DECL is a dllexport'd object.  */
75
76 bool
77 sh_symbian_dllexport_p (tree decl)
78 {
79   tree exp;
80
81   if (   TREE_CODE (decl) != VAR_DECL
82       && TREE_CODE (decl) != FUNCTION_DECL)
83     return false;
84
85   exp = lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl));
86
87   /* Class members get the dllexport status of their class.  */
88   if (exp == NULL)
89     {
90       tree class = sh_symbian_associated_type (decl);
91
92       if (class)
93         exp = lookup_attribute ("dllexport", TYPE_ATTRIBUTES (class));
94     }
95 #if SYMBIAN_DEBUG
96   if (exp)
97     {
98       print_node_brief (stderr, "dllexport:", decl, 0);
99       fprintf (stderr, "\n");
100     }
101   else
102 #if SYMBIAN_DEBUG < 2
103     if (TREE_CODE (decl) != FUNCTION_DECL)
104 #endif
105     {
106       print_node_brief (stderr, "no dllexport:", decl, 0);
107       fprintf (stderr, "\n");
108     }
109 #endif
110   return exp ? true : false;
111 }
112
113 /* Return nonzero if DECL is a dllimport'd object.  */
114
115 static bool
116 sh_symbian_dllimport_p (tree decl)
117 {
118   tree imp;
119
120   if (   TREE_CODE (decl) != VAR_DECL
121       && TREE_CODE (decl) != FUNCTION_DECL)
122     return false;
123
124   imp = lookup_attribute ("dllimport", DECL_ATTRIBUTES (decl));
125   if (imp)
126     return true;
127
128   /* Class members get the dllimport status of their class.  */
129   imp = sh_symbian_associated_type (decl);
130   if (! imp)
131     return false;
132
133   imp = lookup_attribute ("dllimport", TYPE_ATTRIBUTES (imp));
134   if (!imp)
135     return false;
136
137   /* Don't mark defined functions as dllimport.  If the definition itself
138      was marked with dllimport, then sh_symbian_handle_dll_attribute reports
139      an error. This handles the case when the definition overrides an
140      earlier declaration.  */
141   if (TREE_CODE (decl) ==  FUNCTION_DECL
142       && DECL_INITIAL (decl)
143       && !DECL_INLINE (decl))
144     {
145       /* Don't warn about artificial methods.  */
146       if (!DECL_ARTIFICIAL (decl))
147         warning (OPT_Wattributes, "%H function '%D' is defined after prior "
148                  "declaration as dllimport: attribute ignored",
149                  & DECL_SOURCE_LOCATION (decl), decl);
150       return false;
151     }
152
153   /* We ignore the dllimport attribute for inline member functions.
154      This differs from MSVC behavior which treats it like GNUC
155      'extern inline' extension.   */
156   else if (TREE_CODE (decl) == FUNCTION_DECL && DECL_INLINE (decl))
157     {
158       if (extra_warnings)
159         warning (OPT_Wattributes, "%Hinline function '%D' is declared as "
160                  "dllimport: attribute ignored.",
161                  & DECL_SOURCE_LOCATION (decl), decl);
162       return false;
163     }
164
165   /*  Don't allow definitions of static data members in dllimport
166       class.  Just ignore the attribute for vtable data.  */
167   else if (TREE_CODE (decl) == VAR_DECL
168            && TREE_STATIC (decl)
169            && TREE_PUBLIC (decl)
170            && !DECL_EXTERNAL (decl))
171     {
172       if (!DECL_VIRTUAL_P (decl))
173         error ("%Hdefinition of static data member '%D' of dllimport'd class.",
174                & DECL_SOURCE_LOCATION (decl), decl);
175       return false;
176     }
177
178   /* Since we can't treat a pointer to a dllimport'd symbol as a
179      constant address, we turn off the attribute on C++ virtual
180      methods to allow creation of vtables using thunks.  Don't mark
181      artificial methods either (in sh_symbian_associated_type, only
182      COMDAT artificial method get import status from class context).  */
183   else if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE
184            && (DECL_VIRTUAL_P (decl) || DECL_ARTIFICIAL (decl)))
185     return false;
186
187   return true;
188 }
189
190 /* Return nonzero if SYMBOL is marked as being dllexport'd.  */
191
192 bool
193 sh_symbian_dllexport_name_p (const char *symbol)
194 {
195   return strncmp (DLL_EXPORT_PREFIX, symbol,
196                   strlen (DLL_EXPORT_PREFIX)) == 0;
197 }
198
199 /* Return nonzero if SYMBOL is marked as being dllimport'd.  */
200
201
202 bool
203 sh_symbian_dllimport_name_p (const char *symbol)
204 {
205   return strncmp (DLL_IMPORT_PREFIX, symbol,
206                   strlen (DLL_IMPORT_PREFIX)) == 0;
207 }
208
209 /* Mark a DECL as being dllexport'd.
210    Note that we override the previous setting (e.g.: dllimport).  */
211
212 static void
213 sh_symbian_mark_dllexport (tree decl)
214 {
215   const char *oldname;
216   char *newname;
217   rtx rtlname;
218   tree idp;
219
220   rtlname = XEXP (DECL_RTL (decl), 0);
221   if (GET_CODE (rtlname) == MEM)
222     rtlname = XEXP (rtlname, 0);
223   gcc_assert (GET_CODE (rtlname) == SYMBOL_REF);
224   oldname = XSTR (rtlname, 0);
225
226   if (sh_symbian_dllimport_name_p (oldname))
227     {
228      /* Remove DLL_IMPORT_PREFIX.
229         Note - we do not issue a warning here.  In Symbian's environment it
230         is legitimate for a prototype to be marked as dllimport and the
231         corresponding definition to be marked as dllexport.  The prototypes
232         are in headers used everywhere and the definition is in a translation
233         unit which has included the header in order to ensure argument
234         correctness.  */
235       oldname += strlen (DLL_IMPORT_PREFIX);
236       DECL_NON_ADDR_CONST_P (decl) = 0;
237     }
238   else if (sh_symbian_dllexport_name_p (oldname))
239     return; /* Already done.  */
240
241   newname = alloca (strlen (DLL_EXPORT_PREFIX) + strlen (oldname) + 1);
242   sprintf (newname, "%s%s", DLL_EXPORT_PREFIX, oldname);
243
244   /* We pass newname through get_identifier to ensure it has a unique
245      address.  RTL processing can sometimes peek inside the symbol ref
246      and compare the string's addresses to see if two symbols are
247      identical.  */
248   idp = get_identifier (newname);
249
250   XEXP (DECL_RTL (decl), 0) =
251     gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp));
252 }
253
254 /* Mark a DECL as being dllimport'd.  */
255
256 static void
257 sh_symbian_mark_dllimport (tree decl)
258 {
259   const char *oldname;
260   char *newname;
261   tree idp;
262   rtx rtlname;
263   rtx newrtl;
264
265   rtlname = XEXP (DECL_RTL (decl), 0);
266   if (GET_CODE (rtlname) == MEM)
267     rtlname = XEXP (rtlname, 0);
268   gcc_assert (GET_CODE (rtlname) == SYMBOL_REF);
269   oldname = XSTR (rtlname, 0);
270
271   if (sh_symbian_dllexport_name_p (oldname))
272     {
273       error ("%qs declared as both exported to and imported from a DLL",
274              IDENTIFIER_POINTER (DECL_NAME (decl)));
275     }
276   else if (sh_symbian_dllimport_name_p (oldname))
277     {
278       /* Already done, but do a sanity check to prevent assembler errors.  */
279       if (!DECL_EXTERNAL (decl) || !TREE_PUBLIC (decl))
280         error ("%Hfailure in redeclaration of '%D': dllimport'd symbol lacks external linkage.",
281                &DECL_SOURCE_LOCATION (decl), decl);
282     }
283   else
284     {
285       newname = alloca (strlen (DLL_IMPORT_PREFIX) + strlen (oldname) + 1);
286       sprintf (newname, "%s%s", DLL_IMPORT_PREFIX, oldname);
287
288       /* We pass newname through get_identifier to ensure it has a unique
289          address.  RTL processing can sometimes peek inside the symbol ref
290          and compare the string's addresses to see if two symbols are
291          identical.  */
292       idp = get_identifier (newname);
293       newrtl = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp));
294       XEXP (DECL_RTL (decl), 0) = newrtl;
295     }
296 }
297
298 void
299 sh_symbian_encode_section_info (tree decl, rtx rtl, int first)
300 {
301   default_encode_section_info (decl, rtl, first);
302
303   /* Mark the decl so we can tell from the rtl whether
304      the object is dllexport'd or dllimport'd.  */
305   if (sh_symbian_dllexport_p (decl))
306     sh_symbian_mark_dllexport (decl);
307   else if (sh_symbian_dllimport_p (decl))
308     sh_symbian_mark_dllimport (decl);
309   /* It might be that DECL has already been marked as dllimport, but a
310      subsequent definition nullified that.  The attribute is gone but
311      DECL_RTL still has (DLL_IMPORT_PREFIX) prefixed. We need to remove
312      that. Ditto for the DECL_NON_ADDR_CONST_P flag.  */
313   else if (  (TREE_CODE (decl) == FUNCTION_DECL
314            || TREE_CODE (decl) == VAR_DECL)
315            && DECL_RTL (decl) != NULL_RTX
316            && GET_CODE (DECL_RTL (decl)) == MEM
317            && GET_CODE (XEXP (DECL_RTL (decl), 0)) == MEM
318            && GET_CODE (XEXP (XEXP (DECL_RTL (decl), 0), 0)) == SYMBOL_REF
319            && sh_symbian_dllimport_name_p (XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0)))
320     {
321       const char * oldname = XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0);
322       /* Remove DLL_IMPORT_PREFIX.  */
323       tree idp = get_identifier (oldname + strlen (DLL_IMPORT_PREFIX));
324       rtx newrtl = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp));
325
326       warning (0, "%H%s '%D' %s after being referenced with dllimport linkage.",
327                & DECL_SOURCE_LOCATION (decl),
328                TREE_CODE (decl) == VAR_DECL ? "variable" : "function",
329                decl, (DECL_INITIAL (decl) || !DECL_EXTERNAL (decl))
330                ? "defined locally" : "redeclared without dllimport attribute");
331
332       XEXP (DECL_RTL (decl), 0) = newrtl;
333
334       DECL_NON_ADDR_CONST_P (decl) = 0;
335     }
336 }
337
338
339 /* Return the length of a function name prefix
340     that starts with the character 'c'.  */
341
342 static int
343 sh_symbian_get_strip_length (int c)
344 {
345   /* XXX Assumes strlen (DLL_EXPORT_PREFIX) == strlen (DLL_IMPORT_PREFIX).  */
346   return (c == SH_SYMBIAN_FLAG_CHAR[0]) ? strlen (DLL_EXPORT_PREFIX) : 0;
347 }
348
349 /* Return a pointer to a function's name with any
350    and all prefix encodings stripped from it.  */
351
352 const char *
353 sh_symbian_strip_name_encoding (const char *name)
354 {
355   int skip;
356
357   while ((skip = sh_symbian_get_strip_length (*name)))
358     name += skip;
359
360   return name;
361 }
362
363 /* Add the named attribute to the given node.  Copes with both DECLs and
364    TYPEs.  Will only add the attribute if it is not already present.  */
365
366 static void
367 symbian_add_attribute (tree node, const char *attr_name)
368 {
369   tree attrs;
370   tree attr;
371
372   attrs = DECL_P (node) ? DECL_ATTRIBUTES (node) : TYPE_ATTRIBUTES (node);
373
374   if (lookup_attribute (attr_name, attrs) != NULL_TREE)
375     return;
376
377   attr = get_identifier (attr_name);
378
379   (DECL_P (node) ? DECL_ATTRIBUTES (node) : TYPE_ATTRIBUTES (node))
380     = tree_cons (attr, NULL_TREE, attrs);
381
382 #if SYMBIAN_DEBUG
383   fprintf (stderr, "propogate %s attribute", attr_name);
384   print_node_brief (stderr, " to", node, 0);
385   fprintf (stderr, "\n");
386 #endif
387 }
388
389 /* Handle a "dllimport" or "dllexport" attribute;
390    arguments as in struct attribute_spec.handler.  */
391
392 tree
393 sh_symbian_handle_dll_attribute (tree *pnode, tree name, tree args,
394                                  int flags, bool *no_add_attrs)
395 {
396   tree thunk;
397   tree node = *pnode;
398   const char *attr = IDENTIFIER_POINTER (name);
399
400   /* These attributes may apply to structure and union types being
401      created, but otherwise should pass to the declaration involved.  */
402   if (!DECL_P (node))
403     {
404       if (flags & ((int) ATTR_FLAG_DECL_NEXT
405                    | (int) ATTR_FLAG_FUNCTION_NEXT
406                    | (int) ATTR_FLAG_ARRAY_NEXT))
407         {
408           warning (OPT_Wattributes, "%qs attribute ignored", attr);
409           *no_add_attrs = true;
410           return tree_cons (name, args, NULL_TREE);
411         }
412
413       if (TREE_CODE (node) != RECORD_TYPE && TREE_CODE (node) != UNION_TYPE)
414         {
415           warning (OPT_Wattributes, "%qs attribute ignored", attr);
416           *no_add_attrs = true;
417         }
418
419       return NULL_TREE;
420     }
421
422   /* Report error on dllimport ambiguities
423      seen now before they cause any damage.  */
424   else if (is_attribute_p ("dllimport", name))
425     {
426       if (TREE_CODE (node) == VAR_DECL)
427         {
428           if (DECL_INITIAL (node))
429             {
430               error ("%Hvariable %qD definition is marked dllimport.",
431                      & DECL_SOURCE_LOCATION (node), node);
432               *no_add_attrs = true;
433             }
434
435           /* `extern' needn't be specified with dllimport.
436              Specify `extern' now and hope for the best.  Sigh.  */
437           DECL_EXTERNAL (node) = 1;
438           /* Also, implicitly give dllimport'd variables declared within
439              a function global scope, unless declared static.  */
440           if (current_function_decl != NULL_TREE && ! TREE_STATIC (node))
441             TREE_PUBLIC (node) = 1;
442         }
443     }
444
445   /* If the node is an overloaded constructor or destructor, then we must
446      make sure that the attribute is propagated along the overload chain,
447      as it is these overloaded functions which will be emitted, rather than
448      the user declared constructor itself.  */
449   if (TREE_CODE (TREE_TYPE (node)) == METHOD_TYPE
450       && (DECL_CONSTRUCTOR_P (node) || DECL_DESTRUCTOR_P (node)))
451     {
452       tree overload;
453
454       for (overload = OVL_CHAIN (node); overload; overload = OVL_CHAIN (overload))
455         {
456           tree node_args;
457           tree func_args;
458           tree function = OVL_CURRENT (overload);
459
460           if (! function
461               || ! DECL_P (function)
462               || (DECL_CONSTRUCTOR_P (node) && ! DECL_CONSTRUCTOR_P (function))
463               || (DECL_DESTRUCTOR_P (node)  && ! DECL_DESTRUCTOR_P (function)))
464             continue;
465
466           /* The arguments must match as well.  */
467           for (node_args = DECL_ARGUMENTS (node), func_args = DECL_ARGUMENTS (function);
468                node_args && func_args;
469                node_args = TREE_CHAIN (node_args), func_args = TREE_CHAIN (func_args))
470             if (TREE_TYPE (node_args) != TREE_TYPE (func_args))
471               break;
472
473           if (node_args || func_args)
474             {
475               /* We can ignore an extraneous __in_chrg arguments in the node.
476                  GCC generated destructors, for example, will have this.  */
477               if ((node_args == NULL_TREE
478                    || func_args != NULL_TREE)
479                   && strcmp (IDENTIFIER_POINTER (DECL_NAME (node)), "__in_chrg") != 0)
480                 continue;
481             }
482
483           symbian_add_attribute (function, attr);
484
485           /* Propagate the attribute to any function thunks as well.  */
486           for (thunk = DECL_THUNKS (function); thunk; thunk = TREE_CHAIN (thunk))
487             if (TREE_CODE (thunk) == FUNCTION_DECL)
488               symbian_add_attribute (thunk, attr);
489         }
490     }
491
492   if (TREE_CODE (node) == FUNCTION_DECL && DECL_VIRTUAL_P (node))
493     {
494       /* Propagate the attribute to any thunks of this function.  */
495       for (thunk = DECL_THUNKS (node); thunk; thunk = TREE_CHAIN (thunk))
496         if (TREE_CODE (thunk) == FUNCTION_DECL)
497           symbian_add_attribute (thunk, attr);
498     }
499
500   /*  Report error if symbol is not accessible at global scope.  */
501   if (!TREE_PUBLIC (node)
502       && (   TREE_CODE (node) == VAR_DECL
503           || TREE_CODE (node) == FUNCTION_DECL))
504     {
505       error ("%Hexternal linkage required for symbol '%D' because of '%s' attribute.",
506                & DECL_SOURCE_LOCATION (node), node, IDENTIFIER_POINTER (name));
507       *no_add_attrs = true;
508     }
509
510 #if SYMBIAN_DEBUG
511   print_node_brief (stderr, "mark node", node, 0);
512   fprintf (stderr, " as %s\n", attr);
513 #endif
514
515   return NULL_TREE;
516 }
517
518 /* This code implements a specification for exporting the vtable and rtti of
519    classes that have members with the dllexport or dllexport attributes.
520    This specification is defined here:
521
522      http://www.armdevzone.com/EABI/exported_class.txt
523
524    Basically it says that a class's vtable and rtti should be exported if
525    the following rules apply:
526
527    - If it has any non-inline non-pure virtual functions,
528      at least one of these need to be declared dllimport
529      OR any of the constructors is declared dllimport.
530
531    AND
532
533    - The class has an inline constructor/destructor and
534      a key-function (placement of vtable uniquely defined) that
535      is defined in this translation unit.
536
537    The specification also says that for classes which will have their
538    vtables and rtti exported that their base class(es) might also need a
539    similar exporting if:
540
541    - Every base class needs to have its vtable & rtti exported
542      as well, if the following the conditions hold true:
543      + The base class has a non-inline declared non-pure virtual function
544      + The base class is polymorphic (has or inherits any virtual functions)
545        or the base class has any virtual base classes.  */
546 \f
547 /* Decide if a base class of a class should
548    also have its vtable and rtti exported.  */
549
550 static void
551 symbian_possibly_export_base_class (tree base_class)
552 {
553   tree methods;
554   int len;
555
556   if (! (TYPE_CONTAINS_VPTR_P (base_class)))
557     return;
558
559   methods = CLASSTYPE_METHOD_VEC (base_class);
560   len = methods ? TREE_VEC_LENGTH (methods) : 0;
561
562   for (;len --;)
563     {
564       tree member = TREE_VEC_ELT (methods, len);
565
566       if (! member)
567         continue;
568
569       for (member = OVL_CURRENT (member); member; member = OVL_NEXT (member))
570         {
571           if (TREE_CODE (member) != FUNCTION_DECL)
572             continue;
573
574           if (DECL_CONSTRUCTOR_P (member) || DECL_DESTRUCTOR_P (member))
575             continue;
576
577           if (! DECL_VIRTUAL_P (member))
578             continue;
579
580           if (DECL_PURE_VIRTUAL_P (member))
581             continue;
582
583           if (DECL_INLINE (member))
584             continue;
585
586           break;
587         }
588
589       if (member)
590         break;
591     }
592
593   if (len < 0)
594     return;
595
596   /* FIXME: According to the spec this base class should be exported, but
597      a) how do we do this ? and
598      b) it does not appear to be necessary for compliance with the Symbian
599         OS which so far is the only consumer of this code.  */
600 #if SYMBIAN_DEBUG
601   print_node_brief (stderr, "", base_class, 0);
602   fprintf (stderr, " EXPORTed [base class of exported class]\n");
603 #endif
604 }
605
606 /* Decide if a class needs its vtable and rtti exporting.  */
607
608 static bool
609 symbian_export_vtable_and_rtti_p (tree ctype)
610 {
611   bool inline_ctor_dtor;
612   bool dllimport_ctor_dtor;
613   bool dllimport_member;
614   tree binfo, base_binfo;
615   tree methods;
616   tree key;
617   int i;
618   int len;
619
620   /* Make sure that we are examining a class...  */
621   if (TREE_CODE (ctype) != RECORD_TYPE)
622     {
623 #if SYMBIAN_DEBUG
624       print_node_brief (stderr, "", ctype, 0);
625       fprintf (stderr, " does NOT need to be EXPORTed [not a class]\n");
626 #endif
627       return false;
628     }
629
630   /* If the class does not have a key function it
631      does not need to have its vtable exported.  */
632   if ((key = CLASSTYPE_KEY_METHOD (ctype)) == NULL_TREE)
633     {
634 #if SYMBIAN_DEBUG
635       print_node_brief (stderr, "", ctype, 0);
636       fprintf (stderr, " does NOT need to be EXPORTed [no key function]\n");
637 #endif
638       return false;
639     }
640
641   /* If the key fn has not been defined
642      then the class should not be exported.  */
643   if (! TREE_ASM_WRITTEN (key))
644     {
645 #if SYMBIAN_DEBUG
646       print_node_brief (stderr, "", ctype, 0);
647       fprintf (stderr, " does NOT need to be EXPORTed [key function not defined]\n");
648 #endif
649       return false;
650     }
651
652   /* Check the class's member functions.  */
653   inline_ctor_dtor = false;
654   dllimport_ctor_dtor = false;
655   dllimport_member = false;
656
657   methods = CLASSTYPE_METHOD_VEC (ctype);
658   len = methods ? TREE_VEC_LENGTH (methods) : 0;
659
660   for (;len --;)
661     {
662       tree member = TREE_VEC_ELT (methods, len);
663
664       if (! member)
665         continue;
666
667       for (member = OVL_CURRENT (member); member; member = OVL_NEXT (member))
668         {
669           if (TREE_CODE (member) != FUNCTION_DECL)
670             continue;
671
672           if (DECL_CONSTRUCTOR_P (member) || DECL_DESTRUCTOR_P (member))
673             {
674               if (DECL_INLINE (member)
675                   /* Ignore C++ backend created inline ctors/dtors.  */
676                   && (   DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (member)
677                       || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (member)))
678                 inline_ctor_dtor = true;
679
680               if (lookup_attribute ("dllimport", DECL_ATTRIBUTES (member)))
681                 dllimport_ctor_dtor = true;
682             }
683           else
684             {
685               if (DECL_PURE_VIRTUAL_P (member))
686                 continue;
687
688               if (! DECL_VIRTUAL_P (member))
689                 continue;
690
691               if (DECL_INLINE (member))
692                 continue;
693
694               if (lookup_attribute ("dllimport", DECL_ATTRIBUTES (member)))
695                 dllimport_member = true;
696             }
697         }
698     }
699
700   if (! dllimport_member && ! dllimport_ctor_dtor)
701     {
702 #if SYMBIAN_DEBUG
703       print_node_brief (stderr, "", ctype, 0);
704       fprintf (stderr,
705                " does NOT need to be EXPORTed [no non-pure virtuals or ctors/dtors with dllimport]\n");
706 #endif
707       return false;
708     }
709
710   if (! inline_ctor_dtor)
711     {
712 #if SYMBIAN_DEBUG
713       print_node_brief (stderr, "", ctype, 0);
714       fprintf (stderr,
715                " does NOT need to be EXPORTed [no inline ctor/dtor]\n");
716 #endif
717       return false;
718     }
719
720 #if SYMBIAN_DEBUG
721   print_node_brief (stderr, "", ctype, 0);
722   fprintf (stderr, " DOES need to be EXPORTed\n");
723 #endif
724
725   /* Now we must check and possibly export the base classes.  */
726   for (i = 0, binfo = TYPE_BINFO (ctype);
727        BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
728     symbian_possibly_export_base_class (BINFO_TYPE (base_binfo));
729
730   return true;
731 }
732
733 /* Add the named attribute to a class and its vtable and rtti.  */
734
735 static void
736 symbian_add_attribute_to_class_vtable_and_rtti (tree ctype, const char *attr_name)
737 {
738   symbian_add_attribute (ctype, attr_name);
739
740   /* If the vtable exists then they need annotating as well.  */
741   if (CLASSTYPE_VTABLES (ctype))
742     /* XXX - Do we need to annotate any vtables other than the primary ?  */
743     symbian_add_attribute (CLASSTYPE_VTABLES (ctype), attr_name);
744
745   /* If the rtti exists then it needs annotating as well.  */
746   if (TYPE_MAIN_VARIANT (ctype)
747       && CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (ctype)))
748     symbian_add_attribute (CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (ctype)),
749                            attr_name);
750 }
751
752 /* Decide if a class needs to have an attribute because
753    one of its member functions has the attribute.  */
754
755 static bool
756 symbian_class_needs_attribute_p (tree ctype, const char *attribute_name)
757 {
758   /* If the key function has the attribute then the class needs it too.  */
759   if (TYPE_POLYMORPHIC_P (ctype)
760       && CLASSTYPE_KEY_METHOD (ctype)
761       && lookup_attribute (attribute_name,
762                            DECL_ATTRIBUTES (CLASSTYPE_KEY_METHOD (ctype))))
763     return true;
764
765   /* Check the class's member functions.  */
766   if (TREE_CODE (ctype) == RECORD_TYPE)
767     {
768       tree methods = CLASSTYPE_METHOD_VEC (ctype);
769       unsigned int len = methods ? TREE_VEC_LENGTH (methods) : 0;
770
771       for (;len --;)
772         {
773           tree member = TREE_VEC_ELT (methods, len);
774
775           if (! member)
776             continue;
777
778           for (member = OVL_CURRENT (member);
779                member;
780                member = OVL_NEXT (member))
781             {
782               if (TREE_CODE (member) != FUNCTION_DECL)
783                 continue;
784
785               if (DECL_PURE_VIRTUAL_P (member))
786                 continue;
787
788               if (! DECL_VIRTUAL_P (member))
789                 continue;
790
791               if (lookup_attribute (attribute_name, DECL_ATTRIBUTES (member)))
792                 {
793 #if SYMBIAN_DEBUG
794                   print_node_brief (stderr, "", ctype, 0);
795                   fprintf (stderr, " inherits %s because", attribute_name);
796                   print_node_brief (stderr, "", member, 0);
797                   fprintf (stderr, " has it.\n");
798 #endif
799                   return true;
800                 }
801             }
802         }
803     }
804
805 #if SYMBIAN_DEBUG
806   print_node_brief (stderr, "", ctype, 0);
807   fprintf (stderr, " does not inherit %s\n", attribute_name);
808 #endif
809   return false;
810 }
811
812 int
813 symbian_import_export_class (tree ctype, int import_export)
814 {
815   const char *attr_name = NULL;
816
817   /* If we are exporting the class but it does not have the dllexport
818      attribute then we may need to add it.  Similarly imported classes
819      may need the dllimport attribute.  */
820   switch (import_export)
821     {
822     case  1: attr_name = "dllexport"; break;
823     case -1: attr_name = "dllimport"; break;
824     default: break;
825     }
826
827   if (attr_name
828       && ! lookup_attribute (attr_name, TYPE_ATTRIBUTES (ctype)))
829     {
830       if (symbian_class_needs_attribute_p (ctype, attr_name))
831         symbian_add_attribute_to_class_vtable_and_rtti (ctype, attr_name);
832
833       /* Classes can be forced to export their
834          vtable and rtti under certain conditions.  */
835       if (symbian_export_vtable_and_rtti_p (ctype))
836         {
837           symbian_add_attribute_to_class_vtable_and_rtti (ctype, "dllexport");
838
839           /* Make sure that the class and its vtable are exported.  */
840           import_export = 1;
841
842           if (CLASSTYPE_VTABLES (ctype))
843             DECL_EXTERNAL (CLASSTYPE_VTABLES (ctype)) = 1;
844
845           /* Check to make sure that if the class has a key method that
846              it is now on the list of keyed classes.  That way its vtable
847              will be emitted.  */
848           if (CLASSTYPE_KEY_METHOD (ctype))
849             {
850               tree class;
851
852               for (class = keyed_classes; class; class = TREE_CHAIN (class))
853                 if (class == ctype)
854                   break;
855
856               if (class == NULL_TREE)
857                 {
858 #if SYMBIAN_DEBUG
859                   print_node_brief (stderr, "Add node", ctype, 0);
860                   fprintf (stderr, " to the keyed classes list\n");
861 #endif
862                   keyed_classes = tree_cons (NULL_TREE, ctype, keyed_classes);
863                 }
864             }
865
866           /* Make sure that the typeinfo will be emitted as well.  */
867           if (CLASS_TYPE_P (ctype))
868             TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (ctype)))) = 1;
869         }
870     }
871
872   return import_export;
873 }
874
875 /* Dummy definition of this array for cc1 building purposes.  */
876 tree cp_global_trees[CPTI_MAX] __attribute__((weak));
877
878 #if defined ENABLE_TREE_CHECKING && (GCC_VERSION >= 2007)
879
880 /* Dummy version of this G++ function for building cc1.  */
881 void lang_check_failed (const char *, int, const char *) __attribute__((weak));
882
883 void
884 lang_check_failed (const char *file, int line, const char *function)
885 {
886   internal_error ("lang_* check: failed in %s, at %s:%d",
887                   function, trim_filename (file), line);
888 }
889 #endif /* ENABLE_TREE_CHECKING */