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
55static tree
56sh_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
76bool
77sh_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
115static bool
116sh_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
192bool
193sh_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
202bool
203sh_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
212static void
213sh_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_DLLIMPORT_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
256static void
257sh_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
298void
299sh_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_DLLIMPORT_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_DLLIMPORT_P (decl) = 0;
334    }
335}
336
337
338/* Return the length of a function name prefix
339    that starts with the character 'c'.  */
340
341static int
342sh_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
351const char *
352sh_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
365static void
366symbian_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
393tree
394sh_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
551static void
552symbian_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
609static bool
610symbian_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
736static void
737symbian_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
756static bool
757symbian_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
818int
819symbian_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.  */
882tree 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.  */
887void lang_check_failed (const char *, int, const char *) __attribute__((weak));
888
889void
890lang_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