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, 51 Franklin Street, Fifth Floor,
21    Boston, MA 02110-1301, 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 
52 /* Return the type that we should use to determine if DECL is
53    imported or exported.  */
54 
55 static tree
sh_symbian_associated_type(tree decl)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
sh_symbian_dllexport_p(tree decl)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
sh_symbian_dllimport_p(tree decl)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, "function %q+D is defined after prior "
148 		 "declaration as dllimport: attribute ignored",
149 		 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, "inline function %q+D is declared as "
160 		 "dllimport: attribute ignored",
161 		 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 ("definition of static data member %q+D of dllimport'd class",
174 	       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
sh_symbian_dllexport_name_p(const char * symbol)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
sh_symbian_dllimport_name_p(const char * symbol)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
sh_symbian_mark_dllexport(tree decl)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
sh_symbian_mark_dllimport(tree decl)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 ("failure in redeclaration of %q+D: dllimport'd symbol lacks external linkage",
281 	       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
sh_symbian_encode_section_info(tree decl,rtx rtl,int first)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, "%s %q+D %s after being referenced with dllimport linkage",
327 	       TREE_CODE (decl) == VAR_DECL ? "variable" : "function",
328 	       decl, (DECL_INITIAL (decl) || !DECL_EXTERNAL (decl))
329 	       ? "defined locally" : "redeclared without dllimport attribute");
330 
331       XEXP (DECL_RTL (decl), 0) = newrtl;
332 
333       DECL_NON_ADDR_CONST_P (decl) = 0;
334     }
335 }
336 
337 
338 /* Return the length of a function name prefix
339     that starts with the character 'c'.  */
340 
341 static int
sh_symbian_get_strip_length(int c)342 sh_symbian_get_strip_length (int c)
343 {
344   /* XXX Assumes strlen (DLL_EXPORT_PREFIX) == strlen (DLL_IMPORT_PREFIX).  */
345   return (c == SH_SYMBIAN_FLAG_CHAR[0]) ? strlen (DLL_EXPORT_PREFIX) : 0;
346 }
347 
348 /* Return a pointer to a function's name with any
349    and all prefix encodings stripped from it.  */
350 
351 const char *
sh_symbian_strip_name_encoding(const char * name)352 sh_symbian_strip_name_encoding (const char *name)
353 {
354   int skip;
355 
356   while ((skip = sh_symbian_get_strip_length (*name)))
357     name += skip;
358 
359   return name;
360 }
361 
362 /* Add the named attribute to the given node.  Copes with both DECLs and
363    TYPEs.  Will only add the attribute if it is not already present.  */
364 
365 static void
symbian_add_attribute(tree node,const char * attr_name)366 symbian_add_attribute (tree node, const char *attr_name)
367 {
368   tree attrs;
369   tree attr;
370 
371   attrs = DECL_P (node) ? DECL_ATTRIBUTES (node) : TYPE_ATTRIBUTES (node);
372 
373   if (lookup_attribute (attr_name, attrs) != NULL_TREE)
374     return;
375 
376   attr = get_identifier (attr_name);
377 
378   if (DECL_P (node))
379     DECL_ATTRIBUTES (node) = tree_cons (attr, NULL_TREE, attrs);
380   else
381     TYPE_ATTRIBUTES (node) = tree_cons (attr, NULL_TREE, attrs);
382 
383 #if SYMBIAN_DEBUG
384   fprintf (stderr, "propogate %s attribute", attr_name);
385   print_node_brief (stderr, " to", node, 0);
386   fprintf (stderr, "\n");
387 #endif
388 }
389 
390 /* Handle a "dllimport" or "dllexport" attribute;
391    arguments as in struct attribute_spec.handler.  */
392 
393 tree
sh_symbian_handle_dll_attribute(tree * pnode,tree name,tree args,int flags,bool * no_add_attrs)394 sh_symbian_handle_dll_attribute (tree *pnode, tree name, tree args,
395 				 int flags, bool *no_add_attrs)
396 {
397   tree thunk;
398   tree node = *pnode;
399   const char *attr = IDENTIFIER_POINTER (name);
400 
401   /* These attributes may apply to structure and union types being
402      created, but otherwise should pass to the declaration involved.  */
403   if (!DECL_P (node))
404     {
405       if (flags & ((int) ATTR_FLAG_DECL_NEXT
406 		   | (int) ATTR_FLAG_FUNCTION_NEXT
407 		   | (int) ATTR_FLAG_ARRAY_NEXT))
408 	{
409 	  warning (OPT_Wattributes, "%qs attribute ignored", attr);
410 	  *no_add_attrs = true;
411 	  return tree_cons (name, args, NULL_TREE);
412 	}
413 
414       if (TREE_CODE (node) != RECORD_TYPE && TREE_CODE (node) != UNION_TYPE)
415 	{
416 	  warning (OPT_Wattributes, "%qs attribute ignored", attr);
417 	  *no_add_attrs = true;
418 	}
419 
420       return NULL_TREE;
421     }
422 
423   /* Report error on dllimport ambiguities
424      seen now before they cause any damage.  */
425   else if (is_attribute_p ("dllimport", name))
426     {
427       if (TREE_CODE (node) == VAR_DECL)
428 	{
429 	  if (DECL_INITIAL (node))
430 	    {
431 	      error ("variable %q+D definition is marked dllimport",
432 		     node);
433 	      *no_add_attrs = true;
434 	    }
435 
436 	  /* `extern' needn't be specified with dllimport.
437 	     Specify `extern' now and hope for the best.  Sigh.  */
438 	  DECL_EXTERNAL (node) = 1;
439 	  /* Also, implicitly give dllimport'd variables declared within
440 	     a function global scope, unless declared static.  */
441 	  if (current_function_decl != NULL_TREE && ! TREE_STATIC (node))
442   	    TREE_PUBLIC (node) = 1;
443 	}
444     }
445 
446   /* If the node is an overloaded constructor or destructor, then we must
447      make sure that the attribute is propagated along the overload chain,
448      as it is these overloaded functions which will be emitted, rather than
449      the user declared constructor itself.  */
450   if (TREE_CODE (TREE_TYPE (node)) == METHOD_TYPE
451       && (DECL_CONSTRUCTOR_P (node) || DECL_DESTRUCTOR_P (node)))
452     {
453       tree overload;
454 
455       for (overload = OVL_CHAIN (node); overload; overload = OVL_CHAIN (overload))
456 	{
457 	  tree node_args;
458 	  tree func_args;
459 	  tree function = OVL_CURRENT (overload);
460 
461 	  if (! function
462 	      || ! DECL_P (function)
463 	      || (DECL_CONSTRUCTOR_P (node) && ! DECL_CONSTRUCTOR_P (function))
464 	      || (DECL_DESTRUCTOR_P (node)  && ! DECL_DESTRUCTOR_P (function)))
465 	    continue;
466 
467 	  /* The arguments must match as well.  */
468 	  for (node_args = DECL_ARGUMENTS (node), func_args = DECL_ARGUMENTS (function);
469 	       node_args && func_args;
470 	       node_args = TREE_CHAIN (node_args), func_args = TREE_CHAIN (func_args))
471 	    if (TREE_TYPE (node_args) != TREE_TYPE (func_args))
472 	      break;
473 
474 	  if (node_args || func_args)
475 	    {
476 	      /* We can ignore an extraneous __in_chrg arguments in the node.
477 		 GCC generated destructors, for example, will have this.  */
478 	      if ((node_args == NULL_TREE
479 		   || func_args != NULL_TREE)
480 		  && strcmp (IDENTIFIER_POINTER (DECL_NAME (node)), "__in_chrg") != 0)
481 		continue;
482 	    }
483 
484 	  symbian_add_attribute (function, attr);
485 
486 	  /* Propagate the attribute to any function thunks as well.  */
487 	  for (thunk = DECL_THUNKS (function); thunk; thunk = TREE_CHAIN (thunk))
488 	    if (TREE_CODE (thunk) == FUNCTION_DECL)
489 	      symbian_add_attribute (thunk, attr);
490 	}
491     }
492 
493   if (TREE_CODE (node) == FUNCTION_DECL && DECL_VIRTUAL_P (node))
494     {
495       /* Propagate the attribute to any thunks of this function.  */
496       for (thunk = DECL_THUNKS (node); thunk; thunk = TREE_CHAIN (thunk))
497 	if (TREE_CODE (thunk) == FUNCTION_DECL)
498 	  symbian_add_attribute (thunk, attr);
499     }
500 
501   /*  Report error if symbol is not accessible at global scope.  */
502   if (!TREE_PUBLIC (node)
503       && (   TREE_CODE (node) == VAR_DECL
504 	  || TREE_CODE (node) == FUNCTION_DECL))
505     {
506       error ("external linkage required for symbol %q+D because of %qs attribute",
507 	     node, IDENTIFIER_POINTER (name));
508       *no_add_attrs = true;
509     }
510 
511 #if SYMBIAN_DEBUG
512   print_node_brief (stderr, "mark node", node, 0);
513   fprintf (stderr, " as %s\n", attr);
514 #endif
515 
516   return NULL_TREE;
517 }
518 
519 /* This code implements a specification for exporting the vtable and rtti of
520    classes that have members with the dllexport or dllexport attributes.
521    This specification is defined here:
522 
523      http://www.armdevzone.com/EABI/exported_class.txt
524 
525    Basically it says that a class's vtable and rtti should be exported if
526    the following rules apply:
527 
528    - If it has any non-inline non-pure virtual functions,
529      at least one of these need to be declared dllimport
530      OR any of the constructors is declared dllimport.
531 
532    AND
533 
534    - The class has an inline constructor/destructor and
535      a key-function (placement of vtable uniquely defined) that
536      is defined in this translation unit.
537 
538    The specification also says that for classes which will have their
539    vtables and rtti exported that their base class(es) might also need a
540    similar exporting if:
541 
542    - Every base class needs to have its vtable & rtti exported
543      as well, if the following the conditions hold true:
544      + The base class has a non-inline declared non-pure virtual function
545      + The base class is polymorphic (has or inherits any virtual functions)
546        or the base class has any virtual base classes.  */
547 
548 /* Decide if a base class of a class should
549    also have its vtable and rtti exported.  */
550 
551 static void
symbian_possibly_export_base_class(tree base_class)552 symbian_possibly_export_base_class (tree base_class)
553 {
554   VEC(tree,gc) *method_vec;
555   int len;
556 
557   if (! (TYPE_CONTAINS_VPTR_P (base_class)))
558     return;
559 
560   method_vec = CLASSTYPE_METHOD_VEC (base_class);
561   len = method_vec ? VEC_length (tree, method_vec) : 0;
562 
563   for (;len --;)
564     {
565       tree member = VEC_index (tree, method_vec, len);
566 
567       if (! member)
568 	continue;
569 
570       for (member = OVL_CURRENT (member); member; member = OVL_NEXT (member))
571 	{
572 	  if (TREE_CODE (member) != FUNCTION_DECL)
573 	    continue;
574 
575 	  if (DECL_CONSTRUCTOR_P (member) || DECL_DESTRUCTOR_P (member))
576 	    continue;
577 
578 	  if (! DECL_VIRTUAL_P (member))
579 	    continue;
580 
581 	  if (DECL_PURE_VIRTUAL_P (member))
582 	    continue;
583 
584 	  if (DECL_INLINE (member))
585 	    continue;
586 
587 	  break;
588 	}
589 
590       if (member)
591 	break;
592     }
593 
594   if (len < 0)
595     return;
596 
597   /* FIXME: According to the spec this base class should be exported, but
598      a) how do we do this ? and
599      b) it does not appear to be necessary for compliance with the Symbian
600         OS which so far is the only consumer of this code.  */
601 #if SYMBIAN_DEBUG
602   print_node_brief (stderr, "", base_class, 0);
603   fprintf (stderr, " EXPORTed [base class of exported class]\n");
604 #endif
605 }
606 
607 /* Decide if a class needs its vtable and rtti exporting.  */
608 
609 static bool
symbian_export_vtable_and_rtti_p(tree ctype)610 symbian_export_vtable_and_rtti_p (tree ctype)
611 {
612   bool inline_ctor_dtor;
613   bool dllimport_ctor_dtor;
614   bool dllimport_member;
615   tree binfo, base_binfo;
616   VEC(tree,gc) *method_vec;
617   tree key;
618   int i;
619   int len;
620 
621   /* Make sure that we are examining a class...  */
622   if (TREE_CODE (ctype) != RECORD_TYPE)
623     {
624 #if SYMBIAN_DEBUG
625       print_node_brief (stderr, "", ctype, 0);
626       fprintf (stderr, " does NOT need to be EXPORTed [not a class]\n");
627 #endif
628       return false;
629     }
630 
631   /* If the class does not have a key function it
632      does not need to have its vtable exported.  */
633   if ((key = CLASSTYPE_KEY_METHOD (ctype)) == NULL_TREE)
634     {
635 #if SYMBIAN_DEBUG
636       print_node_brief (stderr, "", ctype, 0);
637       fprintf (stderr, " does NOT need to be EXPORTed [no key function]\n");
638 #endif
639       return false;
640     }
641 
642   /* If the key fn has not been defined
643      then the class should not be exported.  */
644   if (! TREE_ASM_WRITTEN (key))
645     {
646 #if SYMBIAN_DEBUG
647       print_node_brief (stderr, "", ctype, 0);
648       fprintf (stderr, " does NOT need to be EXPORTed [key function not defined]\n");
649 #endif
650       return false;
651     }
652 
653   /* Check the class's member functions.  */
654   inline_ctor_dtor = false;
655   dllimport_ctor_dtor = false;
656   dllimport_member = false;
657 
658   method_vec = CLASSTYPE_METHOD_VEC (ctype);
659   len = method_vec ? VEC_length (tree, method_vec) : 0;
660 
661   for (;len --;)
662     {
663       tree member = VEC_index (tree, method_vec, len);
664 
665       if (! member)
666 	continue;
667 
668       for (member = OVL_CURRENT (member); member; member = OVL_NEXT (member))
669 	{
670 	  if (TREE_CODE (member) != FUNCTION_DECL)
671 	    continue;
672 
673 	  if (DECL_CONSTRUCTOR_P (member) || DECL_DESTRUCTOR_P (member))
674 	    {
675 	      if (DECL_INLINE (member)
676 		  /* Ignore C++ backend created inline ctors/dtors.  */
677 		  && (   DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (member)
678 		      || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (member)))
679 		inline_ctor_dtor = true;
680 
681 	      if (lookup_attribute ("dllimport", DECL_ATTRIBUTES (member)))
682 		dllimport_ctor_dtor = true;
683 	    }
684 	  else
685 	    {
686 	      if (DECL_PURE_VIRTUAL_P (member))
687 		continue;
688 
689 	      if (! DECL_VIRTUAL_P (member))
690 		continue;
691 
692 	      if (DECL_INLINE (member))
693 		continue;
694 
695 	      if (lookup_attribute ("dllimport", DECL_ATTRIBUTES (member)))
696 		dllimport_member = true;
697 	    }
698 	}
699     }
700 
701   if (! dllimport_member && ! dllimport_ctor_dtor)
702     {
703 #if SYMBIAN_DEBUG
704       print_node_brief (stderr, "", ctype, 0);
705       fprintf (stderr,
706 	       " does NOT need to be EXPORTed [no non-pure virtuals or ctors/dtors with dllimport]\n");
707 #endif
708       return false;
709     }
710 
711   if (! inline_ctor_dtor)
712     {
713 #if SYMBIAN_DEBUG
714       print_node_brief (stderr, "", ctype, 0);
715       fprintf (stderr,
716 	       " does NOT need to be EXPORTed [no inline ctor/dtor]\n");
717 #endif
718       return false;
719     }
720 
721 #if SYMBIAN_DEBUG
722   print_node_brief (stderr, "", ctype, 0);
723   fprintf (stderr, " DOES need to be EXPORTed\n");
724 #endif
725 
726   /* Now we must check and possibly export the base classes.  */
727   for (i = 0, binfo = TYPE_BINFO (ctype);
728        BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
729     symbian_possibly_export_base_class (BINFO_TYPE (base_binfo));
730 
731   return true;
732 }
733 
734 /* Add the named attribute to a class and its vtable and rtti.  */
735 
736 static void
symbian_add_attribute_to_class_vtable_and_rtti(tree ctype,const char * attr_name)737 symbian_add_attribute_to_class_vtable_and_rtti (tree ctype, const char *attr_name)
738 {
739   symbian_add_attribute (ctype, attr_name);
740 
741   /* If the vtable exists then they need annotating as well.  */
742   if (CLASSTYPE_VTABLES (ctype))
743     /* XXX - Do we need to annotate any vtables other than the primary ?  */
744     symbian_add_attribute (CLASSTYPE_VTABLES (ctype), attr_name);
745 
746   /* If the rtti exists then it needs annotating as well.  */
747   if (TYPE_MAIN_VARIANT (ctype)
748       && CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (ctype)))
749     symbian_add_attribute (CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (ctype)),
750 			   attr_name);
751 }
752 
753 /* Decide if a class needs to have an attribute because
754    one of its member functions has the attribute.  */
755 
756 static bool
symbian_class_needs_attribute_p(tree ctype,const char * attribute_name)757 symbian_class_needs_attribute_p (tree ctype, const char *attribute_name)
758 {
759   VEC(tree,gc) *method_vec;
760 
761   method_vec = CLASSTYPE_METHOD_VEC (ctype);
762 
763   /* If the key function has the attribute then the class needs it too.  */
764   if (TYPE_POLYMORPHIC_P (ctype)
765       && method_vec
766       && lookup_attribute (attribute_name,
767 			   DECL_ATTRIBUTES (VEC_index (tree, method_vec, 0))))
768     return true;
769 
770   /* Check the class's member functions.  */
771   if (TREE_CODE (ctype) == RECORD_TYPE)
772     {
773       unsigned int len;
774 
775       len = method_vec ? VEC_length (tree, method_vec) : 0;
776 
777       for (;len --;)
778 	{
779 	  tree member = VEC_index (tree, method_vec, 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
symbian_import_export_class(tree ctype,int import_export)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
lang_check_failed(const char * file,int line,const char * function)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 */
896