1 /* Routines for C++ support for GCC for a Symbian OS targeted SH backend.
2 Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
4 Most of this code is stolen from i386/winnt.c.
6 This file is part of GCC.
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 3, or (at your
11 option) any later version.
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.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
24 #include "coretypes.h"
32 #include "cp/cp-tree.h" /* We need access to the OVL_... macros. */
34 #include "sh-symbian.h"
37 /* Return the type that we should use to determine if DECL is
38 imported or exported. */
41 sh_symbian_associated_type (tree decl)
45 if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
46 /* Methods now inherit their dllimport/dllexport attributes correctly
47 so there is no need to check their class. In fact it is wrong to
48 check their class since a method can remain unexported from an
52 /* Otherwise we can just take the DECL_CONTEXT as normal. */
53 if (DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl)))
54 t = DECL_CONTEXT (decl);
60 /* Return nonzero if DECL is a dllimport'd object. */
63 sh_symbian_is_dllimported (tree decl)
67 if ( TREE_CODE (decl) != VAR_DECL
68 && TREE_CODE (decl) != FUNCTION_DECL)
71 imp = lookup_attribute ("dllimport", DECL_ATTRIBUTES (decl));
75 /* Class members get the dllimport status of their class. */
76 imp = sh_symbian_associated_type (decl);
80 imp = lookup_attribute ("dllimport", TYPE_ATTRIBUTES (imp));
84 /* Don't mark defined functions as dllimport. If the definition itself
85 was marked with dllimport, then sh_symbian_handle_dll_attribute reports
86 an error. This handles the case when the definition overrides an
87 earlier declaration. */
88 if (TREE_CODE (decl) == FUNCTION_DECL
89 && DECL_INITIAL (decl)
90 && ! DECL_DECLARED_INLINE_P (decl))
92 /* Don't warn about artificial methods. */
93 if (!DECL_ARTIFICIAL (decl))
94 warning (OPT_Wattributes, "function %q+D is defined after prior "
95 "declaration as dllimport: attribute ignored",
100 /* We ignore the dllimport attribute for inline member functions.
101 This differs from MSVC behavior which treats it like GNUC
102 'extern inline' extension. */
103 else if (TREE_CODE (decl) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (decl))
106 warning (OPT_Wattributes, "inline function %q+D is declared as "
107 "dllimport: attribute ignored",
112 /* Don't allow definitions of static data members in dllimport
113 class. Just ignore the attribute for vtable data. */
114 else if (TREE_CODE (decl) == VAR_DECL
115 && TREE_STATIC (decl)
116 && TREE_PUBLIC (decl)
117 && !DECL_EXTERNAL (decl))
119 if (!DECL_VIRTUAL_P (decl))
120 error ("definition of static data member %q+D of dllimport'd class",
125 /* Since we can't treat a pointer to a dllimport'd symbol as a
126 constant address, we turn off the attribute on C++ virtual
127 methods to allow creation of vtables using thunks. Don't mark
128 artificial methods either (in sh_symbian_associated_type, only
129 COMDAT artificial method get import status from class context). */
130 else if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE
131 && (DECL_VIRTUAL_P (decl) || DECL_ARTIFICIAL (decl)))
138 /* This code implements a specification for exporting the vtable and rtti of
139 classes that have members with the dllexport or dllexport attributes.
140 This specification is defined here:
142 http://www.armdevzone.com/EABI/exported_class.txt
144 Basically it says that a class's vtable and rtti should be exported if
145 the following rules apply:
147 - If it has any non-inline non-pure virtual functions,
148 at least one of these need to be declared dllimport
149 OR any of the constructors is declared dllimport.
153 - The class has an inline constructor/destructor and
154 a key-function (placement of vtable uniquely defined) that
155 is defined in this translation unit.
157 The specification also says that for classes which will have their
158 vtables and rtti exported that their base class(es) might also need a
159 similar exporting if:
161 - Every base class needs to have its vtable & rtti exported
162 as well, if the following the conditions hold true:
163 + The base class has a non-inline declared non-pure virtual function
164 + The base class is polymorphic (has or inherits any virtual functions)
165 or the base class has any virtual base classes. */
167 /* Decide if a base class of a class should
168 also have its vtable and rtti exported. */
171 sh_symbian_possibly_export_base_class (tree base_class)
173 VEC(tree,gc) *method_vec;
176 if (! (TYPE_CONTAINS_VPTR_P (base_class)))
179 method_vec = CLASSTYPE_METHOD_VEC (base_class);
180 len = method_vec ? VEC_length (tree, method_vec) : 0;
184 tree member = VEC_index (tree, method_vec, len);
189 for (member = OVL_CURRENT (member); member; member = OVL_NEXT (member))
191 if (TREE_CODE (member) != FUNCTION_DECL)
194 if (DECL_CONSTRUCTOR_P (member) || DECL_DESTRUCTOR_P (member))
197 if (! DECL_VIRTUAL_P (member))
200 if (DECL_PURE_VIRTUAL_P (member))
203 if (DECL_DECLARED_INLINE_P (member))
216 /* FIXME: According to the spec this base class should be exported, but
217 a) how do we do this ? and
218 b) it does not appear to be necessary for compliance with the Symbian
219 OS which so far is the only consumer of this code. */
221 print_node_brief (stderr, "", base_class, 0);
222 fprintf (stderr, " EXPORTed [base class of exported class]\n");
226 /* Add the named attribute to the given node. Copes with both DECLs and
227 TYPEs. Will only add the attribute if it is not already present. */
230 sh_symbian_add_attribute (tree node, const char *attr_name)
235 attrs = DECL_P (node) ? DECL_ATTRIBUTES (node) : TYPE_ATTRIBUTES (node);
237 if (lookup_attribute (attr_name, attrs) != NULL_TREE)
240 attr = get_identifier (attr_name);
243 DECL_ATTRIBUTES (node) = tree_cons (attr, NULL_TREE, attrs);
245 TYPE_ATTRIBUTES (node) = tree_cons (attr, NULL_TREE, attrs);
248 fprintf (stderr, "propagate %s attribute", attr_name);
249 print_node_brief (stderr, " to", node, 0);
250 fprintf (stderr, "\n");
254 /* Add the named attribute to a class and its vtable and rtti. */
257 sh_symbian_add_attribute_to_class_vtable_and_rtti (tree ctype, const char *attr_name)
259 sh_symbian_add_attribute (ctype, attr_name);
261 /* If the vtable exists then they need annotating as well. */
262 if (CLASSTYPE_VTABLES (ctype))
263 /* XXX - Do we need to annotate any vtables other than the primary ? */
264 sh_symbian_add_attribute (CLASSTYPE_VTABLES (ctype), attr_name);
266 /* If the rtti exists then it needs annotating as well. */
267 if (TYPE_MAIN_VARIANT (ctype)
268 && CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (ctype)))
269 sh_symbian_add_attribute (CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (ctype)),
273 /* Decide if a class needs to have an attribute because
274 one of its member functions has the attribute. */
277 sh_symbian_class_needs_attribute (tree ctype, const char *attribute_name)
279 VEC(tree,gc) *method_vec;
281 method_vec = CLASSTYPE_METHOD_VEC (ctype);
283 /* If the key function has the attribute then the class needs it too. */
284 if (TYPE_POLYMORPHIC_P (ctype)
286 && tree_contains_struct [TREE_CODE (ctype), TS_DECL_COMMON] == 1
287 && lookup_attribute (attribute_name,
288 DECL_ATTRIBUTES (VEC_index (tree, method_vec, 0))))
291 /* Check the class's member functions. */
292 if (TREE_CODE (ctype) == RECORD_TYPE)
296 len = method_vec ? VEC_length (tree, method_vec) : 0;
300 tree member = VEC_index (tree, method_vec, len);
305 for (member = OVL_CURRENT (member);
307 member = OVL_NEXT (member))
309 if (TREE_CODE (member) != FUNCTION_DECL)
312 if (DECL_PURE_VIRTUAL_P (member))
315 if (! DECL_VIRTUAL_P (member))
318 if (lookup_attribute (attribute_name, DECL_ATTRIBUTES (member)))
321 print_node_brief (stderr, "", ctype, 0);
322 fprintf (stderr, " inherits %s because", attribute_name);
323 print_node_brief (stderr, "", member, 0);
324 fprintf (stderr, " has it.\n");
333 print_node_brief (stderr, "", ctype, 0);
334 fprintf (stderr, " does not inherit %s\n", attribute_name);
339 /* Decide if a class needs its vtable and rtti exporting. */
342 symbian_export_vtable_and_rtti_p (tree ctype)
344 bool inline_ctor_dtor;
345 bool dllimport_ctor_dtor;
346 bool dllimport_member;
347 tree binfo, base_binfo;
348 VEC(tree,gc) *method_vec;
353 /* Make sure that we are examining a class... */
354 if (TREE_CODE (ctype) != RECORD_TYPE)
357 print_node_brief (stderr, "", ctype, 0);
358 fprintf (stderr, " does NOT need to be EXPORTed [not a class]\n");
363 /* If the class does not have a key function it
364 does not need to have its vtable exported. */
365 if ((key = CLASSTYPE_KEY_METHOD (ctype)) == NULL_TREE)
368 print_node_brief (stderr, "", ctype, 0);
369 fprintf (stderr, " does NOT need to be EXPORTed [no key function]\n");
374 /* If the key fn has not been defined
375 then the class should not be exported. */
376 if (! TREE_ASM_WRITTEN (key))
379 print_node_brief (stderr, "", ctype, 0);
380 fprintf (stderr, " does NOT need to be EXPORTed [key function not defined]\n");
385 /* Check the class's member functions. */
386 inline_ctor_dtor = false;
387 dllimport_ctor_dtor = false;
388 dllimport_member = false;
390 method_vec = CLASSTYPE_METHOD_VEC (ctype);
391 len = method_vec ? VEC_length (tree, method_vec) : 0;
395 tree member = VEC_index (tree, method_vec, len);
400 for (member = OVL_CURRENT (member); member; member = OVL_NEXT (member))
402 if (TREE_CODE (member) != FUNCTION_DECL)
405 if (DECL_CONSTRUCTOR_P (member) || DECL_DESTRUCTOR_P (member))
407 if (DECL_DECLARED_INLINE_P (member)
408 /* Ignore C++ backend created inline ctors/dtors. */
409 && ( DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (member)
410 || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (member)))
411 inline_ctor_dtor = true;
413 if (lookup_attribute ("dllimport", DECL_ATTRIBUTES (member)))
414 dllimport_ctor_dtor = true;
418 if (DECL_PURE_VIRTUAL_P (member))
421 if (! DECL_VIRTUAL_P (member))
424 if (DECL_DECLARED_INLINE_P (member))
427 if (lookup_attribute ("dllimport", DECL_ATTRIBUTES (member)))
428 dllimport_member = true;
433 if (! dllimport_member && ! dllimport_ctor_dtor)
436 print_node_brief (stderr, "", ctype, 0);
438 " does NOT need to be EXPORTed [no non-pure virtuals or ctors/dtors with dllimport]\n");
443 if (! inline_ctor_dtor)
446 print_node_brief (stderr, "", ctype, 0);
448 " does NOT need to be EXPORTed [no inline ctor/dtor]\n");
454 print_node_brief (stderr, "", ctype, 0);
455 fprintf (stderr, " DOES need to be EXPORTed\n");
458 /* Now we must check and possibly export the base classes. */
459 for (i = 0, binfo = TYPE_BINFO (ctype);
460 BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
461 sh_symbian_possibly_export_base_class (BINFO_TYPE (base_binfo));
466 /* Possibly override the decision to export class TYPE. Upon entry
467 IMPORT_EXPORT will contain 1 if the class is going to be exported,
468 -1 if it is going to be imported and 0 otherwise. This function
469 should return the modified value and perform any other actions
470 necessary to support the backend's targeted operating system. */
473 sh_symbian_import_export_class (tree ctype, int import_export)
475 const char *attr_name = NULL;
477 /* If we are exporting the class but it does not have the dllexport
478 attribute then we may need to add it. Similarly imported classes
479 may need the dllimport attribute. */
480 switch (import_export)
482 case 1: attr_name = "dllexport"; break;
483 case -1: attr_name = "dllimport"; break;
488 && ! lookup_attribute (attr_name, TYPE_ATTRIBUTES (ctype)))
490 if (sh_symbian_class_needs_attribute (ctype, attr_name))
491 sh_symbian_add_attribute_to_class_vtable_and_rtti (ctype, attr_name);
493 /* Classes can be forced to export their
494 vtable and rtti under certain conditions. */
495 if (symbian_export_vtable_and_rtti_p (ctype))
497 sh_symbian_add_attribute_to_class_vtable_and_rtti (ctype, "dllexport");
499 /* Make sure that the class and its vtable are exported. */
502 if (CLASSTYPE_VTABLES (ctype))
503 DECL_EXTERNAL (CLASSTYPE_VTABLES (ctype)) = 1;
505 /* Check to make sure that if the class has a key method that
506 it is now on the list of keyed classes. That way its vtable
508 if (CLASSTYPE_KEY_METHOD (ctype))
512 for (class = keyed_classes; class; class = TREE_CHAIN (class))
516 if (class == NULL_TREE)
519 print_node_brief (stderr, "Add node", ctype, 0);
520 fprintf (stderr, " to the keyed classes list\n");
522 keyed_classes = tree_cons (NULL_TREE, ctype, keyed_classes);
526 /* Make sure that the typeinfo will be emitted as well. */
527 if (CLASS_TYPE_P (ctype))
528 TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (ctype)))) = 1;
532 return import_export;
535 /* Handle a "dllimport" or "dllexport" attribute;
536 arguments as in struct attribute_spec.handler. */
539 sh_symbian_handle_dll_attribute (tree *pnode, tree name, tree args,
540 int flags, bool *no_add_attrs)
544 const char *attr = IDENTIFIER_POINTER (name);
546 /* These attributes may apply to structure and union types being
547 created, but otherwise should pass to the declaration involved. */
550 if (flags & ((int) ATTR_FLAG_DECL_NEXT
551 | (int) ATTR_FLAG_FUNCTION_NEXT
552 | (int) ATTR_FLAG_ARRAY_NEXT))
554 warning (OPT_Wattributes, "%qs attribute ignored", attr);
555 *no_add_attrs = true;
556 return tree_cons (name, args, NULL_TREE);
559 if (TREE_CODE (node) != RECORD_TYPE && TREE_CODE (node) != UNION_TYPE)
561 warning (OPT_Wattributes, "%qs attribute ignored", attr);
562 *no_add_attrs = true;
568 /* Report error on dllimport ambiguities
569 seen now before they cause any damage. */
570 else if (is_attribute_p ("dllimport", name))
572 if (TREE_CODE (node) == VAR_DECL)
574 if (DECL_INITIAL (node))
576 error ("variable %q+D definition is marked dllimport",
578 *no_add_attrs = true;
581 /* `extern' needn't be specified with dllimport.
582 Specify `extern' now and hope for the best. Sigh. */
583 DECL_EXTERNAL (node) = 1;
584 /* Also, implicitly give dllimport'd variables declared within
585 a function global scope, unless declared static. */
586 if (current_function_decl != NULL_TREE && ! TREE_STATIC (node))
587 TREE_PUBLIC (node) = 1;
591 /* If the node is an overloaded constructor or destructor, then we must
592 make sure that the attribute is propagated along the overload chain,
593 as it is these overloaded functions which will be emitted, rather than
594 the user declared constructor itself. */
595 if (TREE_CODE (TREE_TYPE (node)) == METHOD_TYPE
596 && (DECL_CONSTRUCTOR_P (node) || DECL_DESTRUCTOR_P (node)))
600 for (overload = OVL_CHAIN (node); overload; overload = OVL_CHAIN (overload))
604 tree function = OVL_CURRENT (overload);
607 || ! DECL_P (function)
608 || (DECL_CONSTRUCTOR_P (node) && ! DECL_CONSTRUCTOR_P (function))
609 || (DECL_DESTRUCTOR_P (node) && ! DECL_DESTRUCTOR_P (function)))
612 /* The arguments must match as well. */
613 for (node_args = DECL_ARGUMENTS (node), func_args = DECL_ARGUMENTS (function);
614 node_args && func_args;
615 node_args = TREE_CHAIN (node_args), func_args = TREE_CHAIN (func_args))
616 if (TREE_TYPE (node_args) != TREE_TYPE (func_args))
619 if (node_args || func_args)
621 /* We can ignore an extraneous __in_chrg arguments in the node.
622 GCC generated destructors, for example, will have this. */
623 if ((node_args == NULL_TREE
624 || func_args != NULL_TREE)
625 && strcmp (IDENTIFIER_POINTER (DECL_NAME (node)), "__in_chrg") != 0)
629 sh_symbian_add_attribute (function, attr);
631 /* Propagate the attribute to any function thunks as well. */
632 for (thunk = DECL_THUNKS (function); thunk; thunk = TREE_CHAIN (thunk))
633 if (TREE_CODE (thunk) == FUNCTION_DECL)
634 sh_symbian_add_attribute (thunk, attr);
638 if (TREE_CODE (node) == FUNCTION_DECL && DECL_VIRTUAL_P (node))
640 /* Propagate the attribute to any thunks of this function. */
641 for (thunk = DECL_THUNKS (node); thunk; thunk = TREE_CHAIN (thunk))
642 if (TREE_CODE (thunk) == FUNCTION_DECL)
643 sh_symbian_add_attribute (thunk, attr);
646 /* Report error if symbol is not accessible at global scope. */
647 if (!TREE_PUBLIC (node)
648 && ( TREE_CODE (node) == VAR_DECL
649 || TREE_CODE (node) == FUNCTION_DECL))
651 error ("external linkage required for symbol %q+D because of %qE attribute",
653 *no_add_attrs = true;
657 print_node_brief (stderr, "mark node", node, 0);
658 fprintf (stderr, " as %s\n", attr);