OSDN Git Service

.:
[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 (eg: 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 defintion to be marked as dllexport.  The prototypes
234         are in headers used everywhere and the defintion 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 desctructor, then we must
452      make sure that the attribute is propogated 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           /* Propogate 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       /* Propogate 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_POLYMORPHIC_P (base_class)
563          || TYPE_USES_VIRTUAL_BASECLASSES (base_class)))
564     return;
565
566   methods = CLASSTYPE_METHOD_VEC (base_class);
567   len = methods ? TREE_VEC_LENGTH (methods) : 0;
568
569   for (;len --;)
570     {
571       tree member = TREE_VEC_ELT (methods, len);
572
573       if (! member)
574         continue;
575
576       for (member = OVL_CURRENT (member); member; member = OVL_NEXT (member))
577         {
578           if (TREE_CODE (member) != FUNCTION_DECL)
579             continue;
580
581           if (DECL_CONSTRUCTOR_P (member) || DECL_DESTRUCTOR_P (member))
582             continue;
583
584           if (! DECL_VIRTUAL_P (member))
585             continue;
586
587           if (DECL_PURE_VIRTUAL_P (member))
588             continue;
589
590           if (DECL_INLINE (member))
591             continue;
592
593           break;
594         }
595
596       if (member)
597         break;
598     }
599
600   if (len < 0)
601     return;
602
603   /* FIXME: According to the spec this base class should be exported, but
604      a) how do we do this ? and
605      b) it does not appear to be necessary for compliance with the Symbian
606         OS which so far is the only consumer of this code.  */
607 #if SYMBIAN_DEBUG
608   print_node_brief (stderr, "", base_class, 0);
609   fprintf (stderr, " EXPORTed [base class of exported class]\n");
610 #endif
611 }
612
613 /* Decide if a class needs its vtable and rtti exporting.  */
614
615 static bool
616 symbian_export_vtable_and_rtti_p (tree ctype)
617 {
618   bool inline_ctor_dtor;
619   bool dllimport_ctor_dtor;
620   bool dllimport_member;
621   tree binfo, base_binfo;
622   tree methods;
623   tree key;
624   int i;
625   int len;
626
627   /* Make sure that we are examining a class...  */
628   if (TREE_CODE (ctype) != RECORD_TYPE)
629     {
630 #if SYMBIAN_DEBUG
631       print_node_brief (stderr, "", ctype, 0);
632       fprintf (stderr, " does NOT need to be EXPORTed [not a class]\n");
633 #endif
634       return false;
635     }
636
637   /* If the class does not have a key function it
638      does not need to have its vtable exported.  */
639   if ((key = CLASSTYPE_KEY_METHOD (ctype)) == NULL_TREE)
640     {
641 #if SYMBIAN_DEBUG
642       print_node_brief (stderr, "", ctype, 0);
643       fprintf (stderr, " does NOT need to be EXPORTed [no key function]\n");
644 #endif
645       return false;
646     }
647
648   /* If the key fn has not been defined
649      then the class should not be exported.  */
650   if (! TREE_ASM_WRITTEN (key))
651     {
652 #if SYMBIAN_DEBUG
653       print_node_brief (stderr, "", ctype, 0);
654       fprintf (stderr, " does NOT need to be EXPORTed [key function not defined]\n");
655 #endif
656       return false;
657     }
658
659   /* Check the class's member functions.  */
660   inline_ctor_dtor = false;
661   dllimport_ctor_dtor = false;
662   dllimport_member = false;
663
664   methods = CLASSTYPE_METHOD_VEC (ctype);
665   len = methods ? TREE_VEC_LENGTH (methods) : 0;
666
667   for (;len --;)
668     {
669       tree member = TREE_VEC_ELT (methods, len);
670
671       if (! member)
672         continue;
673
674       for (member = OVL_CURRENT (member); member; member = OVL_NEXT (member))
675         {
676           if (TREE_CODE (member) != FUNCTION_DECL)
677             continue;
678
679           if (DECL_CONSTRUCTOR_P (member) || DECL_DESTRUCTOR_P (member))
680             {
681               if (DECL_INLINE (member)
682                   /* Ignore C++ backend created inline ctors/dtors.  */
683                   && (   DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (member)
684                       || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (member)))
685                 inline_ctor_dtor = true;
686
687               if (lookup_attribute ("dllimport", DECL_ATTRIBUTES (member)))
688                 dllimport_ctor_dtor = true;
689             }
690           else
691             {
692               if (DECL_PURE_VIRTUAL_P (member))
693                 continue;
694
695               if (! DECL_VIRTUAL_P (member))
696                 continue;
697
698               if (DECL_INLINE (member))
699                 continue;
700
701               if (lookup_attribute ("dllimport", DECL_ATTRIBUTES (member)))
702                 dllimport_member = true;
703             }
704         }
705     }
706
707   if (! dllimport_member && ! dllimport_ctor_dtor)
708     {
709 #if SYMBIAN_DEBUG
710       print_node_brief (stderr, "", ctype, 0);
711       fprintf (stderr,
712                " does NOT need to be EXPORTed [no non-pure virtuals or ctors/dtors with dllimport]\n");
713 #endif
714       return false;
715     }
716
717   if (! inline_ctor_dtor)
718     {
719 #if SYMBIAN_DEBUG
720       print_node_brief (stderr, "", ctype, 0);
721       fprintf (stderr,
722                " does NOT need to be EXPORTed [no inline ctor/dtor]\n");
723 #endif
724       return false;
725     }
726
727 #if SYMBIAN_DEBUG
728   print_node_brief (stderr, "", ctype, 0);
729   fprintf (stderr, " DOES need to be EXPORTed\n");
730 #endif
731
732   /* Now we must check and possibly export the base classes.  */
733   for (i = 0, binfo = TYPE_BINFO (ctype);
734        BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
735     symbian_possibly_export_base_class (BINFO_TYPE (base_binfo));
736
737   return true;
738 }
739
740 /* Add the named attribute to a class and its vtable and rtti.  */
741
742 static void
743 symbian_add_attribute_to_class_vtable_and_rtti (tree ctype, const char *attr_name)
744 {
745   symbian_add_attribute (ctype, attr_name);
746
747   /* If the vtable exists then they need annotating as well.  */
748   if (CLASSTYPE_VTABLES (ctype))
749     /* XXX - Do we need to annotate any vtables other than the primary ?  */
750     symbian_add_attribute (CLASSTYPE_VTABLES (ctype), attr_name);
751
752   /* If the rtti exists then it needs annotating as well.  */
753   if (TYPE_MAIN_VARIANT (ctype)
754       && CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (ctype)))
755     symbian_add_attribute (CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (ctype)),
756                            attr_name);
757 }
758
759 /* Decide if a class needs to have an attribute because
760    one of its member functions has the attribute.  */
761
762 static bool
763 symbian_class_needs_attribute_p (tree ctype, const char *attribute_name)
764 {
765   /* If the key function has the attribute then the class needs it too.  */
766   if (TYPE_POLYMORPHIC_P (ctype)
767       && CLASSTYPE_KEY_METHOD (ctype)
768       && lookup_attribute (attribute_name,
769                            DECL_ATTRIBUTES (CLASSTYPE_KEY_METHOD (ctype))))
770     return true;
771
772   /* Check the class's member functions.  */
773   if (TREE_CODE (ctype) == RECORD_TYPE)
774     {
775       tree methods = CLASSTYPE_METHOD_VEC (ctype);
776       unsigned int len = methods ? TREE_VEC_LENGTH (methods) : 0;
777
778       for (;len --;)
779         {
780           tree member = TREE_VEC_ELT (methods, len);
781
782           if (! member)
783             continue;
784
785           for (member = OVL_CURRENT (member);
786                member;
787                member = OVL_NEXT (member))
788             {
789               if (TREE_CODE (member) != FUNCTION_DECL)
790                 continue;
791
792               if (DECL_PURE_VIRTUAL_P (member))
793                 continue;
794
795               if (! DECL_VIRTUAL_P (member))
796                 continue;
797
798               if (lookup_attribute (attribute_name, DECL_ATTRIBUTES (member)))
799                 {
800 #if SYMBIAN_DEBUG
801                   print_node_brief (stderr, "", ctype, 0);
802                   fprintf (stderr, " inherits %s because", attribute_name);
803                   print_node_brief (stderr, "", member, 0);
804                   fprintf (stderr, " has it.\n");
805 #endif
806                   return true;
807                 }
808             }
809         }
810     }
811
812 #if SYMBIAN_DEBUG
813   print_node_brief (stderr, "", ctype, 0);
814   fprintf (stderr, " does not inherit %s\n", attribute_name);
815 #endif
816   return false;
817 }
818
819 int
820 symbian_import_export_class (tree ctype, int import_export)
821 {
822   const char *attr_name = NULL;
823
824   /* If we are exporting the class but it does not have the dllexport
825      attribute then we may need to add it.  Similarly imported classes
826      may need the dllimport attribute.  */
827   switch (import_export)
828     {
829     case  1: attr_name = "dllexport"; break;
830     case -1: attr_name = "dllimport"; break;
831     default: break;
832     }
833
834   if (attr_name
835       && ! lookup_attribute (attr_name, TYPE_ATTRIBUTES (ctype)))
836     {
837       if (symbian_class_needs_attribute_p (ctype, attr_name))
838         symbian_add_attribute_to_class_vtable_and_rtti (ctype, attr_name);
839
840       /* Classes can be forced to export their
841          vtable and rtti under certain conditions.  */
842       if (symbian_export_vtable_and_rtti_p (ctype))
843         {
844           symbian_add_attribute_to_class_vtable_and_rtti (ctype, "dllexport");
845
846           /* Make sure that the class and its vtable are exported.  */
847           import_export = 1;
848
849           if (CLASSTYPE_VTABLES (ctype))
850             DECL_EXTERNAL (CLASSTYPE_VTABLES (ctype)) = 1;
851
852           /* Check to make sure that if the class has a key method that
853              it is now on the list of keyed classes.  That way its vtable
854              will be emitted.  */
855           if (CLASSTYPE_KEY_METHOD (ctype))
856             {
857               tree class;
858
859               for (class = keyed_classes; class; class = TREE_CHAIN (class))
860                 if (class == ctype)
861                   break;
862
863               if (class == NULL_TREE)
864                 {
865 #if SYMBIAN_DEBUG
866                   print_node_brief (stderr, "Add node", ctype, 0);
867                   fprintf (stderr, " to the keyed classes list\n");
868 #endif
869                   keyed_classes = tree_cons (NULL_TREE, ctype, keyed_classes);
870                 }
871             }
872
873           /* Make sure that the typeinfo will be emitted as well.  */
874           if (CLASS_TYPE_P (ctype))
875             TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (ctype)))) = 1;
876         }
877     }
878
879   return import_export;
880 }
881
882 /* Dummy defintion of this array for cc1 building purposes.  */
883 tree cp_global_trees[CPTI_MAX] __attribute__((weak));
884
885 #if defined ENABLE_TREE_CHECKING && (GCC_VERSION >= 2007)
886
887 /* Dummy version of this G++ function for building cc1.  */
888 void lang_check_failed (const char *, int, const char *) __attribute__((weak));
889
890 void
891 lang_check_failed (const char *file, int line, const char *function)
892 {
893   internal_error ("lang_* check: failed in %s, at %s:%d",
894                   function, trim_filename (file), line);
895 }
896 #endif /* ENABLE_TREE_CHECKING */