--- /dev/null
+/* Routines for GCC for a Symbian OS targeted SH backend, shared by
+ both the C and C++ compilers.
+ Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
+ Contributed by RedHat.
+ Most of this code is stolen from i386/winnt.c.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "rtl.h"
+#include "output.h"
+#include "flags.h"
+#include "tree.h"
+#include "expr.h"
+#include "tm_p.h"
+#include "toplev.h"
+#include "sh-symbian.h"
+
+/* Return nonzero if SYMBOL is marked as being dllexport'd. */
+
+bool
+sh_symbian_is_dllexported_name (const char *symbol)
+{
+ return strncmp (DLL_EXPORT_PREFIX, symbol,
+ strlen (DLL_EXPORT_PREFIX)) == 0;
+}
+
+/* Return nonzero if SYMBOL is marked as being dllimport'd. */
+
+static bool
+sh_symbian_is_dllimported_name (const char *symbol)
+{
+ return strncmp (DLL_IMPORT_PREFIX, symbol,
+ strlen (DLL_IMPORT_PREFIX)) == 0;
+}
+
+/* Return nonzero if DECL is a dllexport'd object. */
+
+bool
+sh_symbian_is_dllexported (tree decl)
+{
+ tree exp;
+
+ if ( TREE_CODE (decl) != VAR_DECL
+ && TREE_CODE (decl) != FUNCTION_DECL)
+ return false;
+
+ exp = lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl));
+
+ /* Class members get the dllexport status of their class. */
+ if (exp == NULL)
+ {
+ tree class = sh_symbian_associated_type (decl);
+
+ if (class)
+ exp = lookup_attribute ("dllexport", TYPE_ATTRIBUTES (class));
+ }
+#if SYMBIAN_DEBUG
+ if (exp)
+ {
+ print_node_brief (stderr, "dllexport:", decl, 0);
+ fprintf (stderr, "\n");
+ }
+ else
+#if SYMBIAN_DEBUG < 2
+ if (TREE_CODE (decl) != FUNCTION_DECL)
+#endif
+ {
+ print_node_brief (stderr, "no dllexport:", decl, 0);
+ fprintf (stderr, "\n");
+ }
+#endif
+ return exp ? true : false;
+}
+
+/* Mark a DECL as being dllimport'd. */
+
+static void
+sh_symbian_mark_dllimport (tree decl)
+{
+ const char *oldname;
+ char *newname;
+ tree idp;
+ rtx rtlname;
+ rtx newrtl;
+
+ rtlname = XEXP (DECL_RTL (decl), 0);
+ if (MEM_P (rtlname))
+ rtlname = XEXP (rtlname, 0);
+ gcc_assert (GET_CODE (rtlname) == SYMBOL_REF);
+ oldname = XSTR (rtlname, 0);
+
+ if (sh_symbian_is_dllexported_name (oldname))
+ {
+ error ("%qE declared as both exported to and imported from a DLL",
+ DECL_NAME (decl));
+ }
+ else if (sh_symbian_is_dllimported_name (oldname))
+ {
+ /* Already done, but do a sanity check to prevent assembler errors. */
+ if (!DECL_EXTERNAL (decl) || !TREE_PUBLIC (decl))
+ error ("failure in redeclaration of %q+D: dllimport'd symbol lacks external linkage",
+ decl);
+ }
+ else
+ {
+ newname = (char *) alloca (strlen (DLL_IMPORT_PREFIX) + strlen (oldname) + 1);
+ sprintf (newname, "%s%s", DLL_IMPORT_PREFIX, oldname);
+
+ /* We pass newname through get_identifier to ensure it has a unique
+ address. RTL processing can sometimes peek inside the symbol ref
+ and compare the string's addresses to see if two symbols are
+ identical. */
+ idp = get_identifier (newname);
+ newrtl = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp));
+ XEXP (DECL_RTL (decl), 0) = newrtl;
+ }
+}
+
+/* Mark a DECL as being dllexport'd.
+ Note that we override the previous setting (e.g.: dllimport). */
+
+static void
+sh_symbian_mark_dllexport (tree decl)
+{
+ const char *oldname;
+ char *newname;
+ rtx rtlname;
+ tree idp;
+
+ rtlname = XEXP (DECL_RTL (decl), 0);
+ if (MEM_P (rtlname))
+ rtlname = XEXP (rtlname, 0);
+ gcc_assert (GET_CODE (rtlname) == SYMBOL_REF);
+ oldname = XSTR (rtlname, 0);
+
+ if (sh_symbian_is_dllimported_name (oldname))
+ {
+ /* Remove DLL_IMPORT_PREFIX.
+ Note - we do not issue a warning here. In Symbian's environment it
+ is legitimate for a prototype to be marked as dllimport and the
+ corresponding definition to be marked as dllexport. The prototypes
+ are in headers used everywhere and the definition is in a translation
+ unit which has included the header in order to ensure argument
+ correctness. */
+ oldname += strlen (DLL_IMPORT_PREFIX);
+ DECL_DLLIMPORT_P (decl) = 0;
+ }
+ else if (sh_symbian_is_dllexported_name (oldname))
+ return; /* Already done. */
+
+ newname = (char *) alloca (strlen (DLL_EXPORT_PREFIX) + strlen (oldname) + 1);
+ sprintf (newname, "%s%s", DLL_EXPORT_PREFIX, oldname);
+
+ /* We pass newname through get_identifier to ensure it has a unique
+ address. RTL processing can sometimes peek inside the symbol ref
+ and compare the string's addresses to see if two symbols are
+ identical. */
+ idp = get_identifier (newname);
+
+ XEXP (DECL_RTL (decl), 0) =
+ gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp));
+}
+
+void
+sh_symbian_encode_section_info (tree decl, rtx rtl, int first)
+{
+ default_encode_section_info (decl, rtl, first);
+
+ /* Mark the decl so we can tell from the rtl whether
+ the object is dllexport'd or dllimport'd. */
+ if (sh_symbian_is_dllexported (decl))
+ sh_symbian_mark_dllexport (decl);
+ else if (sh_symbian_is_dllimported (decl))
+ sh_symbian_mark_dllimport (decl);
+ /* It might be that DECL has already been marked as dllimport, but a
+ subsequent definition nullified that. The attribute is gone but
+ DECL_RTL still has (DLL_IMPORT_PREFIX) prefixed. We need to remove
+ that. Ditto for the DECL_DLLIMPORT_P flag. */
+ else if ( (TREE_CODE (decl) == FUNCTION_DECL
+ || TREE_CODE (decl) == VAR_DECL)
+ && DECL_RTL (decl) != NULL_RTX
+ && MEM_P (DECL_RTL (decl))
+ && MEM_P (XEXP (DECL_RTL (decl), 0))
+ && GET_CODE (XEXP (XEXP (DECL_RTL (decl), 0), 0)) == SYMBOL_REF
+ && sh_symbian_is_dllimported_name (XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0)))
+ {
+ const char * oldname = XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0);
+ /* Remove DLL_IMPORT_PREFIX. */
+ tree idp = get_identifier (oldname + strlen (DLL_IMPORT_PREFIX));
+ rtx newrtl = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp));
+
+ warning (0, "%s %q+D %s after being referenced with dllimport linkage",
+ TREE_CODE (decl) == VAR_DECL ? "variable" : "function",
+ decl, (DECL_INITIAL (decl) || !DECL_EXTERNAL (decl))
+ ? "defined locally" : "redeclared without dllimport attribute");
+
+ XEXP (DECL_RTL (decl), 0) = newrtl;
+
+ DECL_DLLIMPORT_P (decl) = 0;
+ }
+}
+
+/* Return the length of a function name prefix
+ that starts with the character 'c'. */
+
+static int
+sh_symbian_get_strip_length (int c)
+{
+ /* XXX Assumes strlen (DLL_EXPORT_PREFIX) == strlen (DLL_IMPORT_PREFIX). */
+ return (c == SH_SYMBIAN_FLAG_CHAR[0]) ? strlen (DLL_EXPORT_PREFIX) : 0;
+}
+
+/* Return a pointer to a function's name with any
+ and all prefix encodings stripped from it. */
+
+const char *
+sh_symbian_strip_name_encoding (const char *name)
+{
+ int skip;
+
+ while ((skip = sh_symbian_get_strip_length (*name)))
+ name += skip;
+
+ return name;
+}
+
-/* Routines for GCC for a Symbian OS targeted SH backend.
+/* Routines for C++ support for GCC for a Symbian OS targeted SH backend.
Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
Contributed by RedHat.
Most of this code is stolen from i386/winnt.c.
#include "tm_p.h"
#include "cp/cp-tree.h" /* We need access to the OVL_... macros. */
#include "toplev.h"
-
-/* Select the level of debugging information to display.
- 0 for no debugging.
- 1 for informative messages about decisions to add attributes
- 2 for verbose information about what is being done. */
-#define SYMBIAN_DEBUG 0
-/* #define SYMBIAN_DEBUG 1 */
-/* #define SYMBIAN_DEBUG 2 */
-
-/* A unique character to encode declspec encoded objects. */
-#define SH_SYMBIAN_FLAG_CHAR "$"
-
-/* Unique strings to prefix exported and imported objects. */
-#define DLL_IMPORT_PREFIX SH_SYMBIAN_FLAG_CHAR "i."
-#define DLL_EXPORT_PREFIX SH_SYMBIAN_FLAG_CHAR "e."
+#include "sh-symbian.h"
\f
/* Return the type that we should use to determine if DECL is
imported or exported. */
-static tree
+tree
sh_symbian_associated_type (tree decl)
{
tree t = NULL_TREE;
return t;
}
-/* Return nonzero if DECL is a dllexport'd object. */
-
-bool
-sh_symbian_dllexport_p (tree decl)
-{
- tree exp;
-
- if ( TREE_CODE (decl) != VAR_DECL
- && TREE_CODE (decl) != FUNCTION_DECL)
- return false;
-
- exp = lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl));
-
- /* Class members get the dllexport status of their class. */
- if (exp == NULL)
- {
- tree class = sh_symbian_associated_type (decl);
-
- if (class)
- exp = lookup_attribute ("dllexport", TYPE_ATTRIBUTES (class));
- }
-#if SYMBIAN_DEBUG
- if (exp)
- {
- print_node_brief (stderr, "dllexport:", decl, 0);
- fprintf (stderr, "\n");
- }
- else
-#if SYMBIAN_DEBUG < 2
- if (TREE_CODE (decl) != FUNCTION_DECL)
-#endif
- {
- print_node_brief (stderr, "no dllexport:", decl, 0);
- fprintf (stderr, "\n");
- }
-#endif
- return exp ? true : false;
-}
-
+\f
/* Return nonzero if DECL is a dllimport'd object. */
-static bool
-sh_symbian_dllimport_p (tree decl)
+bool
+sh_symbian_is_dllimported (tree decl)
{
tree imp;
return true;
}
-/* Return nonzero if SYMBOL is marked as being dllexport'd. */
-
-bool
-sh_symbian_dllexport_name_p (const char *symbol)
-{
- return strncmp (DLL_EXPORT_PREFIX, symbol,
- strlen (DLL_EXPORT_PREFIX)) == 0;
-}
-
-/* Return nonzero if SYMBOL is marked as being dllimport'd. */
+\f
+/* This code implements a specification for exporting the vtable and rtti of
+ classes that have members with the dllexport or dllexport attributes.
+ This specification is defined here:
+ http://www.armdevzone.com/EABI/exported_class.txt
-bool
-sh_symbian_dllimport_name_p (const char *symbol)
-{
- return strncmp (DLL_IMPORT_PREFIX, symbol,
- strlen (DLL_IMPORT_PREFIX)) == 0;
-}
+ Basically it says that a class's vtable and rtti should be exported if
+ the following rules apply:
-/* Mark a DECL as being dllexport'd.
- Note that we override the previous setting (e.g.: dllimport). */
+ - If it has any non-inline non-pure virtual functions,
+ at least one of these need to be declared dllimport
+ OR any of the constructors is declared dllimport.
-static void
-sh_symbian_mark_dllexport (tree decl)
-{
- const char *oldname;
- char *newname;
- rtx rtlname;
- tree idp;
-
- rtlname = XEXP (DECL_RTL (decl), 0);
- if (MEM_P (rtlname))
- rtlname = XEXP (rtlname, 0);
- gcc_assert (GET_CODE (rtlname) == SYMBOL_REF);
- oldname = XSTR (rtlname, 0);
-
- if (sh_symbian_dllimport_name_p (oldname))
- {
- /* Remove DLL_IMPORT_PREFIX.
- Note - we do not issue a warning here. In Symbian's environment it
- is legitimate for a prototype to be marked as dllimport and the
- corresponding definition to be marked as dllexport. The prototypes
- are in headers used everywhere and the definition is in a translation
- unit which has included the header in order to ensure argument
- correctness. */
- oldname += strlen (DLL_IMPORT_PREFIX);
- DECL_DLLIMPORT_P (decl) = 0;
- }
- else if (sh_symbian_dllexport_name_p (oldname))
- return; /* Already done. */
+ AND
- newname = alloca (strlen (DLL_EXPORT_PREFIX) + strlen (oldname) + 1);
- sprintf (newname, "%s%s", DLL_EXPORT_PREFIX, oldname);
+ - The class has an inline constructor/destructor and
+ a key-function (placement of vtable uniquely defined) that
+ is defined in this translation unit.
- /* We pass newname through get_identifier to ensure it has a unique
- address. RTL processing can sometimes peek inside the symbol ref
- and compare the string's addresses to see if two symbols are
- identical. */
- idp = get_identifier (newname);
+ The specification also says that for classes which will have their
+ vtables and rtti exported that their base class(es) might also need a
+ similar exporting if:
- XEXP (DECL_RTL (decl), 0) =
- gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp));
-}
+ - Every base class needs to have its vtable & rtti exported
+ as well, if the following the conditions hold true:
+ + The base class has a non-inline declared non-pure virtual function
+ + The base class is polymorphic (has or inherits any virtual functions)
+ or the base class has any virtual base classes. */
-/* Mark a DECL as being dllimport'd. */
+/* Decide if a base class of a class should
+ also have its vtable and rtti exported. */
static void
-sh_symbian_mark_dllimport (tree decl)
+sh_symbian_possibly_export_base_class (tree base_class)
{
- const char *oldname;
- char *newname;
- tree idp;
- rtx rtlname;
- rtx newrtl;
-
- rtlname = XEXP (DECL_RTL (decl), 0);
- if (MEM_P (rtlname))
- rtlname = XEXP (rtlname, 0);
- gcc_assert (GET_CODE (rtlname) == SYMBOL_REF);
- oldname = XSTR (rtlname, 0);
-
- if (sh_symbian_dllexport_name_p (oldname))
- {
- error ("%qE declared as both exported to and imported from a DLL",
- DECL_NAME (decl));
- }
- else if (sh_symbian_dllimport_name_p (oldname))
- {
- /* Already done, but do a sanity check to prevent assembler errors. */
- if (!DECL_EXTERNAL (decl) || !TREE_PUBLIC (decl))
- error ("failure in redeclaration of %q+D: dllimport'd symbol lacks external linkage",
- decl);
- }
- else
- {
- newname = alloca (strlen (DLL_IMPORT_PREFIX) + strlen (oldname) + 1);
- sprintf (newname, "%s%s", DLL_IMPORT_PREFIX, oldname);
-
- /* We pass newname through get_identifier to ensure it has a unique
- address. RTL processing can sometimes peek inside the symbol ref
- and compare the string's addresses to see if two symbols are
- identical. */
- idp = get_identifier (newname);
- newrtl = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp));
- XEXP (DECL_RTL (decl), 0) = newrtl;
- }
-}
+ VEC(tree,gc) *method_vec;
+ int len;
-void
-sh_symbian_encode_section_info (tree decl, rtx rtl, int first)
-{
- default_encode_section_info (decl, rtl, first);
-
- /* Mark the decl so we can tell from the rtl whether
- the object is dllexport'd or dllimport'd. */
- if (sh_symbian_dllexport_p (decl))
- sh_symbian_mark_dllexport (decl);
- else if (sh_symbian_dllimport_p (decl))
- sh_symbian_mark_dllimport (decl);
- /* It might be that DECL has already been marked as dllimport, but a
- subsequent definition nullified that. The attribute is gone but
- DECL_RTL still has (DLL_IMPORT_PREFIX) prefixed. We need to remove
- that. Ditto for the DECL_DLLIMPORT_P flag. */
- else if ( (TREE_CODE (decl) == FUNCTION_DECL
- || TREE_CODE (decl) == VAR_DECL)
- && DECL_RTL (decl) != NULL_RTX
- && MEM_P (DECL_RTL (decl))
- && MEM_P (XEXP (DECL_RTL (decl), 0))
- && GET_CODE (XEXP (XEXP (DECL_RTL (decl), 0), 0)) == SYMBOL_REF
- && sh_symbian_dllimport_name_p (XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0)))
+ if (! (TYPE_CONTAINS_VPTR_P (base_class)))
+ return;
+
+ method_vec = CLASSTYPE_METHOD_VEC (base_class);
+ len = method_vec ? VEC_length (tree, method_vec) : 0;
+
+ for (;len --;)
{
- const char * oldname = XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0);
- /* Remove DLL_IMPORT_PREFIX. */
- tree idp = get_identifier (oldname + strlen (DLL_IMPORT_PREFIX));
- rtx newrtl = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp));
+ tree member = VEC_index (tree, method_vec, len);
- warning (0, "%s %q+D %s after being referenced with dllimport linkage",
- TREE_CODE (decl) == VAR_DECL ? "variable" : "function",
- decl, (DECL_INITIAL (decl) || !DECL_EXTERNAL (decl))
- ? "defined locally" : "redeclared without dllimport attribute");
+ if (! member)
+ continue;
- XEXP (DECL_RTL (decl), 0) = newrtl;
+ for (member = OVL_CURRENT (member); member; member = OVL_NEXT (member))
+ {
+ if (TREE_CODE (member) != FUNCTION_DECL)
+ continue;
- DECL_DLLIMPORT_P (decl) = 0;
- }
-}
+ if (DECL_CONSTRUCTOR_P (member) || DECL_DESTRUCTOR_P (member))
+ continue;
+ if (! DECL_VIRTUAL_P (member))
+ continue;
-/* Return the length of a function name prefix
- that starts with the character 'c'. */
+ if (DECL_PURE_VIRTUAL_P (member))
+ continue;
-static int
-sh_symbian_get_strip_length (int c)
-{
- /* XXX Assumes strlen (DLL_EXPORT_PREFIX) == strlen (DLL_IMPORT_PREFIX). */
- return (c == SH_SYMBIAN_FLAG_CHAR[0]) ? strlen (DLL_EXPORT_PREFIX) : 0;
-}
+ if (DECL_DECLARED_INLINE_P (member))
+ continue;
-/* Return a pointer to a function's name with any
- and all prefix encodings stripped from it. */
+ break;
+ }
-const char *
-sh_symbian_strip_name_encoding (const char *name)
-{
- int skip;
+ if (member)
+ break;
+ }
- while ((skip = sh_symbian_get_strip_length (*name)))
- name += skip;
+ if (len < 0)
+ return;
- return name;
+ /* FIXME: According to the spec this base class should be exported, but
+ a) how do we do this ? and
+ b) it does not appear to be necessary for compliance with the Symbian
+ OS which so far is the only consumer of this code. */
+#if SYMBIAN_DEBUG
+ print_node_brief (stderr, "", base_class, 0);
+ fprintf (stderr, " EXPORTed [base class of exported class]\n");
+#endif
}
/* Add the named attribute to the given node. Copes with both DECLs and
TYPEs. Will only add the attribute if it is not already present. */
static void
-symbian_add_attribute (tree node, const char *attr_name)
+sh_symbian_add_attribute (tree node, const char *attr_name)
{
tree attrs;
tree attr;
#endif
}
-/* Handle a "dllimport" or "dllexport" attribute;
- arguments as in struct attribute_spec.handler. */
+/* Add the named attribute to a class and its vtable and rtti. */
-tree
-sh_symbian_handle_dll_attribute (tree *pnode, tree name, tree args,
- int flags, bool *no_add_attrs)
+static void
+sh_symbian_add_attribute_to_class_vtable_and_rtti (tree ctype, const char *attr_name)
{
- tree thunk;
- tree node = *pnode;
- const char *attr = IDENTIFIER_POINTER (name);
-
- /* These attributes may apply to structure and union types being
- created, but otherwise should pass to the declaration involved. */
- if (!DECL_P (node))
- {
- if (flags & ((int) ATTR_FLAG_DECL_NEXT
- | (int) ATTR_FLAG_FUNCTION_NEXT
- | (int) ATTR_FLAG_ARRAY_NEXT))
- {
- warning (OPT_Wattributes, "%qs attribute ignored", attr);
- *no_add_attrs = true;
- return tree_cons (name, args, NULL_TREE);
- }
-
- if (TREE_CODE (node) != RECORD_TYPE && TREE_CODE (node) != UNION_TYPE)
- {
- warning (OPT_Wattributes, "%qs attribute ignored", attr);
- *no_add_attrs = true;
- }
-
- return NULL_TREE;
- }
-
- /* Report error on dllimport ambiguities
- seen now before they cause any damage. */
- else if (is_attribute_p ("dllimport", name))
- {
- if (TREE_CODE (node) == VAR_DECL)
- {
- if (DECL_INITIAL (node))
- {
- error ("variable %q+D definition is marked dllimport",
- node);
- *no_add_attrs = true;
- }
-
- /* `extern' needn't be specified with dllimport.
- Specify `extern' now and hope for the best. Sigh. */
- DECL_EXTERNAL (node) = 1;
- /* Also, implicitly give dllimport'd variables declared within
- a function global scope, unless declared static. */
- if (current_function_decl != NULL_TREE && ! TREE_STATIC (node))
- TREE_PUBLIC (node) = 1;
- }
- }
-
- /* If the node is an overloaded constructor or destructor, then we must
- make sure that the attribute is propagated along the overload chain,
- as it is these overloaded functions which will be emitted, rather than
- the user declared constructor itself. */
- if (TREE_CODE (TREE_TYPE (node)) == METHOD_TYPE
- && (DECL_CONSTRUCTOR_P (node) || DECL_DESTRUCTOR_P (node)))
- {
- tree overload;
-
- for (overload = OVL_CHAIN (node); overload; overload = OVL_CHAIN (overload))
- {
- tree node_args;
- tree func_args;
- tree function = OVL_CURRENT (overload);
-
- if (! function
- || ! DECL_P (function)
- || (DECL_CONSTRUCTOR_P (node) && ! DECL_CONSTRUCTOR_P (function))
- || (DECL_DESTRUCTOR_P (node) && ! DECL_DESTRUCTOR_P (function)))
- continue;
-
- /* The arguments must match as well. */
- for (node_args = DECL_ARGUMENTS (node), func_args = DECL_ARGUMENTS (function);
- node_args && func_args;
- node_args = TREE_CHAIN (node_args), func_args = TREE_CHAIN (func_args))
- if (TREE_TYPE (node_args) != TREE_TYPE (func_args))
- break;
-
- if (node_args || func_args)
- {
- /* We can ignore an extraneous __in_chrg arguments in the node.
- GCC generated destructors, for example, will have this. */
- if ((node_args == NULL_TREE
- || func_args != NULL_TREE)
- && strcmp (IDENTIFIER_POINTER (DECL_NAME (node)), "__in_chrg") != 0)
- continue;
- }
-
- symbian_add_attribute (function, attr);
-
- /* Propagate the attribute to any function thunks as well. */
- for (thunk = DECL_THUNKS (function); thunk; thunk = TREE_CHAIN (thunk))
- if (TREE_CODE (thunk) == FUNCTION_DECL)
- symbian_add_attribute (thunk, attr);
- }
- }
-
- if (TREE_CODE (node) == FUNCTION_DECL && DECL_VIRTUAL_P (node))
- {
- /* Propagate the attribute to any thunks of this function. */
- for (thunk = DECL_THUNKS (node); thunk; thunk = TREE_CHAIN (thunk))
- if (TREE_CODE (thunk) == FUNCTION_DECL)
- symbian_add_attribute (thunk, attr);
- }
+ sh_symbian_add_attribute (ctype, attr_name);
- /* Report error if symbol is not accessible at global scope. */
- if (!TREE_PUBLIC (node)
- && ( TREE_CODE (node) == VAR_DECL
- || TREE_CODE (node) == FUNCTION_DECL))
- {
- error ("external linkage required for symbol %q+D because of %qE attribute",
- node, name);
- *no_add_attrs = true;
- }
-
-#if SYMBIAN_DEBUG
- print_node_brief (stderr, "mark node", node, 0);
- fprintf (stderr, " as %s\n", attr);
-#endif
+ /* If the vtable exists then they need annotating as well. */
+ if (CLASSTYPE_VTABLES (ctype))
+ /* XXX - Do we need to annotate any vtables other than the primary ? */
+ sh_symbian_add_attribute (CLASSTYPE_VTABLES (ctype), attr_name);
- return NULL_TREE;
+ /* If the rtti exists then it needs annotating as well. */
+ if (TYPE_MAIN_VARIANT (ctype)
+ && CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (ctype)))
+ sh_symbian_add_attribute (CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (ctype)),
+ attr_name);
}
-/* This code implements a specification for exporting the vtable and rtti of
- classes that have members with the dllexport or dllexport attributes.
- This specification is defined here:
-
- http://www.armdevzone.com/EABI/exported_class.txt
-
- Basically it says that a class's vtable and rtti should be exported if
- the following rules apply:
-
- - If it has any non-inline non-pure virtual functions,
- at least one of these need to be declared dllimport
- OR any of the constructors is declared dllimport.
-
- AND
-
- - The class has an inline constructor/destructor and
- a key-function (placement of vtable uniquely defined) that
- is defined in this translation unit.
-
- The specification also says that for classes which will have their
- vtables and rtti exported that their base class(es) might also need a
- similar exporting if:
-
- - Every base class needs to have its vtable & rtti exported
- as well, if the following the conditions hold true:
- + The base class has a non-inline declared non-pure virtual function
- + The base class is polymorphic (has or inherits any virtual functions)
- or the base class has any virtual base classes. */
-\f
-/* Decide if a base class of a class should
- also have its vtable and rtti exported. */
+/* Decide if a class needs to have an attribute because
+ one of its member functions has the attribute. */
-static void
-symbian_possibly_export_base_class (tree base_class)
+static bool
+sh_symbian_class_needs_attribute (tree ctype, const char *attribute_name)
{
VEC(tree,gc) *method_vec;
- int len;
- if (! (TYPE_CONTAINS_VPTR_P (base_class)))
- return;
+ method_vec = CLASSTYPE_METHOD_VEC (ctype);
- method_vec = CLASSTYPE_METHOD_VEC (base_class);
- len = method_vec ? VEC_length (tree, method_vec) : 0;
+ /* If the key function has the attribute then the class needs it too. */
+ if (TYPE_POLYMORPHIC_P (ctype)
+ && method_vec
+ && tree_contains_struct [TREE_CODE (ctype), TS_DECL_COMMON] == 1
+ && lookup_attribute (attribute_name,
+ DECL_ATTRIBUTES (VEC_index (tree, method_vec, 0))))
+ return true;
- for (;len --;)
+ /* Check the class's member functions. */
+ if (TREE_CODE (ctype) == RECORD_TYPE)
{
- tree member = VEC_index (tree, method_vec, len);
+ unsigned int len;
- if (! member)
- continue;
+ len = method_vec ? VEC_length (tree, method_vec) : 0;
- for (member = OVL_CURRENT (member); member; member = OVL_NEXT (member))
+ for (;len --;)
{
- if (TREE_CODE (member) != FUNCTION_DECL)
- continue;
+ tree member = VEC_index (tree, method_vec, len);
- if (DECL_CONSTRUCTOR_P (member) || DECL_DESTRUCTOR_P (member))
+ if (! member)
continue;
- if (! DECL_VIRTUAL_P (member))
- continue;
+ for (member = OVL_CURRENT (member);
+ member;
+ member = OVL_NEXT (member))
+ {
+ if (TREE_CODE (member) != FUNCTION_DECL)
+ continue;
- if (DECL_PURE_VIRTUAL_P (member))
- continue;
+ if (DECL_PURE_VIRTUAL_P (member))
+ continue;
- if (DECL_DECLARED_INLINE_P (member))
- continue;
+ if (! DECL_VIRTUAL_P (member))
+ continue;
- break;
+ if (lookup_attribute (attribute_name, DECL_ATTRIBUTES (member)))
+ {
+#if SYMBIAN_DEBUG
+ print_node_brief (stderr, "", ctype, 0);
+ fprintf (stderr, " inherits %s because", attribute_name);
+ print_node_brief (stderr, "", member, 0);
+ fprintf (stderr, " has it.\n");
+#endif
+ return true;
+ }
+ }
}
-
- if (member)
- break;
}
- if (len < 0)
- return;
-
- /* FIXME: According to the spec this base class should be exported, but
- a) how do we do this ? and
- b) it does not appear to be necessary for compliance with the Symbian
- OS which so far is the only consumer of this code. */
#if SYMBIAN_DEBUG
- print_node_brief (stderr, "", base_class, 0);
- fprintf (stderr, " EXPORTed [base class of exported class]\n");
+ print_node_brief (stderr, "", ctype, 0);
+ fprintf (stderr, " does not inherit %s\n", attribute_name);
#endif
+ return false;
}
/* Decide if a class needs its vtable and rtti exporting. */
/* Now we must check and possibly export the base classes. */
for (i = 0, binfo = TYPE_BINFO (ctype);
BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
- symbian_possibly_export_base_class (BINFO_TYPE (base_binfo));
+ sh_symbian_possibly_export_base_class (BINFO_TYPE (base_binfo));
return true;
}
-/* Add the named attribute to a class and its vtable and rtti. */
-
-static void
-symbian_add_attribute_to_class_vtable_and_rtti (tree ctype, const char *attr_name)
-{
- symbian_add_attribute (ctype, attr_name);
-
- /* If the vtable exists then they need annotating as well. */
- if (CLASSTYPE_VTABLES (ctype))
- /* XXX - Do we need to annotate any vtables other than the primary ? */
- symbian_add_attribute (CLASSTYPE_VTABLES (ctype), attr_name);
-
- /* If the rtti exists then it needs annotating as well. */
- if (TYPE_MAIN_VARIANT (ctype)
- && CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (ctype)))
- symbian_add_attribute (CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (ctype)),
- attr_name);
-}
-
-/* Decide if a class needs to have an attribute because
- one of its member functions has the attribute. */
-
-static bool
-symbian_class_needs_attribute_p (tree ctype, const char *attribute_name)
-{
- VEC(tree,gc) *method_vec;
-
- method_vec = CLASSTYPE_METHOD_VEC (ctype);
-
- /* If the key function has the attribute then the class needs it too. */
- if (TYPE_POLYMORPHIC_P (ctype)
- && method_vec
- && lookup_attribute (attribute_name,
- DECL_ATTRIBUTES (VEC_index (tree, method_vec, 0))))
- return true;
-
- /* Check the class's member functions. */
- if (TREE_CODE (ctype) == RECORD_TYPE)
- {
- unsigned int len;
-
- len = method_vec ? VEC_length (tree, method_vec) : 0;
-
- for (;len --;)
- {
- tree member = VEC_index (tree, method_vec, len);
-
- if (! member)
- continue;
-
- for (member = OVL_CURRENT (member);
- member;
- member = OVL_NEXT (member))
- {
- if (TREE_CODE (member) != FUNCTION_DECL)
- continue;
-
- if (DECL_PURE_VIRTUAL_P (member))
- continue;
-
- if (! DECL_VIRTUAL_P (member))
- continue;
-
- if (lookup_attribute (attribute_name, DECL_ATTRIBUTES (member)))
- {
-#if SYMBIAN_DEBUG
- print_node_brief (stderr, "", ctype, 0);
- fprintf (stderr, " inherits %s because", attribute_name);
- print_node_brief (stderr, "", member, 0);
- fprintf (stderr, " has it.\n");
-#endif
- return true;
- }
- }
- }
- }
-
-#if SYMBIAN_DEBUG
- print_node_brief (stderr, "", ctype, 0);
- fprintf (stderr, " does not inherit %s\n", attribute_name);
-#endif
- return false;
-}
+/* Possibly override the decision to export class TYPE. Upon entry
+ IMPORT_EXPORT will contain 1 if the class is going to be exported,
+ -1 if it is going to be imported and 0 otherwise. This function
+ should return the modified value and perform any other actions
+ necessary to support the backend's targeted operating system. */
int
-symbian_import_export_class (tree ctype, int import_export)
+sh_symbian_import_export_class (tree ctype, int import_export)
{
const char *attr_name = NULL;
if (attr_name
&& ! lookup_attribute (attr_name, TYPE_ATTRIBUTES (ctype)))
{
- if (symbian_class_needs_attribute_p (ctype, attr_name))
- symbian_add_attribute_to_class_vtable_and_rtti (ctype, attr_name);
+ if (sh_symbian_class_needs_attribute (ctype, attr_name))
+ sh_symbian_add_attribute_to_class_vtable_and_rtti (ctype, attr_name);
/* Classes can be forced to export their
vtable and rtti under certain conditions. */
if (symbian_export_vtable_and_rtti_p (ctype))
{
- symbian_add_attribute_to_class_vtable_and_rtti (ctype, "dllexport");
+ sh_symbian_add_attribute_to_class_vtable_and_rtti (ctype, "dllexport");
/* Make sure that the class and its vtable are exported. */
import_export = 1;
return import_export;
}
-/* Dummy definition of this array for cc1 building purposes. */
-tree cp_global_trees[CPTI_MAX] __attribute__((weak));
+/* Handle a "dllimport" or "dllexport" attribute;
+ arguments as in struct attribute_spec.handler. */
-#if defined ENABLE_TREE_CHECKING && (GCC_VERSION >= 2007)
+tree
+sh_symbian_handle_dll_attribute (tree *pnode, tree name, tree args,
+ int flags, bool *no_add_attrs)
+{
+ tree thunk;
+ tree node = *pnode;
+ const char *attr = IDENTIFIER_POINTER (name);
-/* Dummy version of this G++ function for building cc1. */
-void lang_check_failed (const char *, int, const char *) __attribute__((weak));
+ /* These attributes may apply to structure and union types being
+ created, but otherwise should pass to the declaration involved. */
+ if (!DECL_P (node))
+ {
+ if (flags & ((int) ATTR_FLAG_DECL_NEXT
+ | (int) ATTR_FLAG_FUNCTION_NEXT
+ | (int) ATTR_FLAG_ARRAY_NEXT))
+ {
+ warning (OPT_Wattributes, "%qs attribute ignored", attr);
+ *no_add_attrs = true;
+ return tree_cons (name, args, NULL_TREE);
+ }
-void
-lang_check_failed (const char *file, int line, const char *function)
-{
- internal_error ("lang_* check: failed in %s, at %s:%d",
- function, trim_filename (file), line);
+ if (TREE_CODE (node) != RECORD_TYPE && TREE_CODE (node) != UNION_TYPE)
+ {
+ warning (OPT_Wattributes, "%qs attribute ignored", attr);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+ }
+
+ /* Report error on dllimport ambiguities
+ seen now before they cause any damage. */
+ else if (is_attribute_p ("dllimport", name))
+ {
+ if (TREE_CODE (node) == VAR_DECL)
+ {
+ if (DECL_INITIAL (node))
+ {
+ error ("variable %q+D definition is marked dllimport",
+ node);
+ *no_add_attrs = true;
+ }
+
+ /* `extern' needn't be specified with dllimport.
+ Specify `extern' now and hope for the best. Sigh. */
+ DECL_EXTERNAL (node) = 1;
+ /* Also, implicitly give dllimport'd variables declared within
+ a function global scope, unless declared static. */
+ if (current_function_decl != NULL_TREE && ! TREE_STATIC (node))
+ TREE_PUBLIC (node) = 1;
+ }
+ }
+
+ /* If the node is an overloaded constructor or destructor, then we must
+ make sure that the attribute is propagated along the overload chain,
+ as it is these overloaded functions which will be emitted, rather than
+ the user declared constructor itself. */
+ if (TREE_CODE (TREE_TYPE (node)) == METHOD_TYPE
+ && (DECL_CONSTRUCTOR_P (node) || DECL_DESTRUCTOR_P (node)))
+ {
+ tree overload;
+
+ for (overload = OVL_CHAIN (node); overload; overload = OVL_CHAIN (overload))
+ {
+ tree node_args;
+ tree func_args;
+ tree function = OVL_CURRENT (overload);
+
+ if (! function
+ || ! DECL_P (function)
+ || (DECL_CONSTRUCTOR_P (node) && ! DECL_CONSTRUCTOR_P (function))
+ || (DECL_DESTRUCTOR_P (node) && ! DECL_DESTRUCTOR_P (function)))
+ continue;
+
+ /* The arguments must match as well. */
+ for (node_args = DECL_ARGUMENTS (node), func_args = DECL_ARGUMENTS (function);
+ node_args && func_args;
+ node_args = TREE_CHAIN (node_args), func_args = TREE_CHAIN (func_args))
+ if (TREE_TYPE (node_args) != TREE_TYPE (func_args))
+ break;
+
+ if (node_args || func_args)
+ {
+ /* We can ignore an extraneous __in_chrg arguments in the node.
+ GCC generated destructors, for example, will have this. */
+ if ((node_args == NULL_TREE
+ || func_args != NULL_TREE)
+ && strcmp (IDENTIFIER_POINTER (DECL_NAME (node)), "__in_chrg") != 0)
+ continue;
+ }
+
+ sh_symbian_add_attribute (function, attr);
+
+ /* Propagate the attribute to any function thunks as well. */
+ for (thunk = DECL_THUNKS (function); thunk; thunk = TREE_CHAIN (thunk))
+ if (TREE_CODE (thunk) == FUNCTION_DECL)
+ sh_symbian_add_attribute (thunk, attr);
+ }
+ }
+
+ if (TREE_CODE (node) == FUNCTION_DECL && DECL_VIRTUAL_P (node))
+ {
+ /* Propagate the attribute to any thunks of this function. */
+ for (thunk = DECL_THUNKS (node); thunk; thunk = TREE_CHAIN (thunk))
+ if (TREE_CODE (thunk) == FUNCTION_DECL)
+ sh_symbian_add_attribute (thunk, attr);
+ }
+
+ /* Report error if symbol is not accessible at global scope. */
+ if (!TREE_PUBLIC (node)
+ && ( TREE_CODE (node) == VAR_DECL
+ || TREE_CODE (node) == FUNCTION_DECL))
+ {
+ error ("external linkage required for symbol %q+D because of %qE attribute",
+ node, name);
+ *no_add_attrs = true;
+ }
+
+#if SYMBIAN_DEBUG
+ print_node_brief (stderr, "mark node", node, 0);
+ fprintf (stderr, " as %s\n", attr);
+#endif
+
+ return NULL_TREE;
}
-#endif /* ENABLE_TREE_CHECKING */