OSDN Git Service

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