This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFA: Add SH Symbian port


Hi Joern, Hi Alex,

  Please could I have approval to apply the patch below.  It adds
  support for an SH port targeted at the Symbian OS.  This work was
  done by Red Hat under contract to Symbian and Renesas and they would
  now like the code contributed.

  The patch makes use of the recently accepted patch to add an
  import_export_class field to the gcc_target structure and it also
  needs a binutils patch which I will be submitting shortly.  All of
  the changes to the normal parts of the SH backend are protected by
  the definition of a macro called SYMBIAN.

Cheers
  Nick

gcc/ChangeLog
2004-07-06  Nick Clifton  <nickc@redhat.com>

	* config.gcc: Add *-symbian-elf support to the general SH
	target.
        * config/sh/sh.c: Add gcc_target structure initialisers for
	use by the sh-symbian-elf target.
        (print_operand): Add support for the naked attribute.
        (sh_expand_prologue): Likewise.
        (sh_expand_epilogue): Likewise.
        (sh_need_epilogue): Likewise.
        (sh_attribute): Add naked, dllimport and dllexport
	attributes.
        (sh_file_start): Create a .directive section.
        (sh_reorg): Call sh_symbian_reorg.
        * config/sh/symbian-post.h: New header file.  Contains
	definitions of macros that override definitions provided in
	earlier headers.
        * config/sh/symbian-pre.h: New header file.  Define SYMBIAN
	and other macros necessary to set up the Symbian environment.
        * config/sh/t-symbian: New makefile fragment.  Define the
	build rules for the support files used by the Symbian target.
        * config/sh/symbian.c: New source file.  Contains all of the
	SH backend functions necessary to support the sh-symbian-elf
	target.
        * config/sh/sh-protos.h: Add prototypes for the functions
	defined in symbian.c

Index: config.gcc
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config.gcc,v
retrieving revision 1.464
diff -c -3 -p -r1.464 config.gcc
*** config.gcc	5 Jul 2004 19:49:10 -0000	1.464
--- config.gcc	6 Jul 2004 15:04:42 -0000
*************** sh-*-elf* | sh[12346l]*-*-elf* | sh*-*-k
*** 1730,1735 ****
--- 1730,1741 ----
  		tm_file="${tm_file} sh/sh64.h"
  		extra_headers="shmedia.h ushmedia.h sshmedia.h"
  		;;
+ 	*-symbian-elf)
+ 		tmake_file="sh/t-symbian"
+ 		tm_file="sh/symbian-pre.h sh/little.h ${tm_file} sh/symbian-post.h"
+ 		extra_objs="symbian.o"
+ 		extra_parts="crt1.o crti.o crtn.o crtbegin.o crtend.o crtbeginS.o crtendS.o"
+ 		;;	
  	esac
  	# sed el/eb endian suffixes away to avoid confusion with sh[23]e
  	case `echo ${target} | sed 's/e[lb]-/-/'` in
Index: config/sh/sh-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/sh/sh-protos.h,v
retrieving revision 1.55
diff -c -3 -p -r1.55 sh-protos.h
*** config/sh/sh-protos.h	10 May 2004 23:25:13 -0000	1.55
--- config/sh/sh-protos.h	6 Jul 2004 15:04:42 -0000
*************** extern const char *sh_pch_valid_p (const
*** 144,146 ****
--- 144,163 ----
  extern bool sh_promote_prototypes (tree);
  
  #endif /* ! GCC_SH_PROTOS_H */
+ 
+ #ifdef SYMBIAN
+ extern bool         sh_symbian_dllimport_name_p       (const char *);
+ extern const char * sh_symbian_strip_name_encoding    (const char *);
+ extern bool         sh_symbian_dllexport_name_p       (const char *);
+ extern void         sh_symbian_reorg                  (void);
+ extern int          symbian_import_export_class       (tree, int);
+ #ifdef TREE_CODE
+ extern bool         sh_symbian_dllexport_p            (tree);
+ extern bool         sh_symbian_naked_function_p       (tree);
+ extern tree         sh_symbian_handle_naked_attribute (tree *, tree, tree, int, bool *);
+ extern tree         sh_symbian_handle_dll_attribute   (tree *, tree, tree, int, bool *);
+ #ifdef RTX_CODE
+ extern void         sh_symbian_encode_section_info    (tree, rtx, int);
+ #endif
+ #endif
+ #endif /* SYMBIAN */
Index: config/sh/sh.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/sh/sh.c,v
retrieving revision 1.275
diff -c -3 -p -r1.275 sh.c
*** config/sh/sh.c	3 Jul 2004 11:56:43 -0000	1.275
--- config/sh/sh.c	6 Jul 2004 15:04:52 -0000
*************** static tree sh_build_builtin_va_list (vo
*** 446,451 ****
--- 446,462 ----
  /* Return current register pressure for regmode.  */
  #define CURR_REGMODE_PRESSURE(MODE) 	curr_regmode_pressure[((MODE) == SImode) ? 0 : 1]
  
+ #ifdef SYMBIAN
+ 
+ #undef  TARGET_ENCODE_SECTION_INFO
+ #define TARGET_ENCODE_SECTION_INFO	sh_symbian_encode_section_info
+ #undef  TARGET_STRIP_NAME_ENCODING
+ #define TARGET_STRIP_NAME_ENCODING	sh_symbian_strip_name_encoding
+ #undef  TARGET_CXX_IMPORT_EXPORT_CLASS
+ #define TARGET_CXX_IMPORT_EXPORT_CLASS  symbian_import_export_class
+ 
+ #endif /* SYMBIAN */
+ 
  struct gcc_target targetm = TARGET_INITIALIZER;
  
  /* Print the operand address in x to the stream.  */
*************** print_operand_address (FILE *stream, rtx
*** 526,531 ****
--- 537,546 ----
  void
  print_operand (FILE *stream, rtx x, int code)
  {
+ #ifdef SYMBIAN
+   static int skip_nop = 0;
+ #endif
+ 
    switch (code)
      {
      case '.':
*************** print_operand (FILE *stream, rtx x, int 
*** 542,551 ****
--- 557,577 ----
  	fprintf (stream, "trapa #%d", trap_exit);
        else if (sh_cfun_interrupt_handler_p ())
  	fprintf (stream, "rte");
+ #ifdef SYMBIAN
+       else if (sh_symbian_naked_function_p (current_function_decl))
+ 	/* We know that a %# is about to come,
+ 	   and we do not want it to emit an nop.  */
+ 	skip_nop = 1;
+ #endif
        else
  	fprintf (stream, "rts");
        break;
      case '#':
+ #ifdef SYMBIAN
+       if (skip_nop)
+ 	skip_nop = 0;
+       else
+ #endif
        /* Output a nop if there's nothing in the delay slot.  */
        if (dbr_sequence_length () == 0)
  	fprintf (stream, "\n\tnop");
*************** sh_file_start (void)
*** 1426,1431 ****
--- 1452,1463 ----
  {
    default_file_start ();
  
+ #ifdef SYMBIAN
+   /* Declare the .directive section before it is used.  */
+   fputs ("\t.section .directive, \"SM\", @progbits, 1\n", asm_out_file);
+   fputs ("\t.asciz \"#<SYMEDIT>#\\n\"\n", asm_out_file);
+ #endif
+   
    if (TARGET_ELF)
      /* We need to show the text section with the proper
         attributes as in TEXT_SECTION_ASM_OP, before dwarf2out
*************** sh_reorg (void)
*** 3902,3907 ****
--- 3934,3943 ----
    rtx r0_rtx = gen_rtx_REG (Pmode, 0);
    rtx r0_inc_rtx = gen_rtx_POST_INC (Pmode, r0_rtx);
  
+ #ifdef SYMBIAN
+   sh_symbian_reorg ();
+ #endif
+ 
    first = get_insns ();
  
    /* We must split call insns before introducing `mova's.  If we're
*************** sh_expand_prologue (void)
*** 5321,5326 ****
--- 5357,5367 ----
    int save_flags = target_flags;
    int pretend_args;
  
+ #ifdef SYMBIAN
+   if (sh_symbian_naked_function_p (current_function_decl))
+     return;
+ #endif
+ 
    current_function_interrupt = sh_cfun_interrupt_handler_p ();
  
    /* We have pretend args if we had an object sent partially in registers
*************** sh_expand_epilogue (bool sibcall_p)
*** 5684,5689 ****
--- 5725,5735 ----
    int fpscr_deferred = 0;
    int e = sibcall_p ? -1 : 1;
  
+ #ifdef SYMBIAN
+   if (sh_symbian_naked_function_p (current_function_decl))
+     return;
+ #endif
+ 
    d = calc_live_regs (&live_regs_mask);
  
    save_size = d;
*************** static int sh_need_epilogue_known = 0;
*** 5929,5934 ****
--- 5975,5985 ----
  int
  sh_need_epilogue (void)
  {
+ #ifdef SYMBIAN
+   if (sh_symbian_naked_function_p (current_function_decl))
+     return sh_need_epilogue_known = 0;
+ #endif
+ 
    if (! sh_need_epilogue_known)
      {
        rtx epilogue;
*************** const struct attribute_spec sh_attribute
*** 6965,6970 ****
--- 7016,7034 ----
    { "sp_switch",         1, 1, true,  false, false, sh_handle_sp_switch_attribute },
    { "trap_exit",         1, 1, true,  false, false, sh_handle_trap_exit_attribute },
    { "renesas",           0, 0, false, true, false, sh_handle_renesas_attribute },
+ #ifdef SYMBIAN
+   /* Symbian support adds three new attributes:
+      dllexport - for exporting a function/variable that will live in a dll
+      dllimport - for importing a function/variable from a dll
+      naked     - functions without a prologue or epilogue.
+      
+      Microsoft allows multiple declspecs in one __declspec, separating
+      them with spaces.  We do NOT support this.  Instead, use __declspec
+      multiple times.  */
+   { "dllimport",         0, 0, true,  false, false, sh_symbian_handle_dll_attribute },
+   { "dllexport",         0, 0, true,  false, false, sh_symbian_handle_dll_attribute },
+   { "naked",             0, 0, true,  false, false, sh_symbian_handle_naked_attribute },
+ #endif
    { NULL,                0, 0, false, false, false, NULL }
  };
  
*** /dev/null	2004-02-18 15:26:44.000000000 +0000
--- config/sh/symbian-post.h	2004-07-06 12:46:35.000000000 +0100
***************
*** 0 ****
--- 1,89 ----
+ /* Definitions for the Symbian OS running on an SH part.
+    This file is included after all the other target specific headers.
+ 
+    Copyright (C) 2004 Free Software Foundation, Inc.
+    Contributed by Red Hat.
+ 
+    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 2, 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 COPYING.  If not, write to the
+    Free Software Foundation, 59 Temple Place - Suite 330,
+    Boston, MA 02111-1307, USA.  */
+ 
+ #undef  TARGET_VERSION
+ #define TARGET_VERSION \
+   fputs (" (Renesas SH for Symbian OS)", stderr);
+ 
+ #undef  LINK_EMUL_PREFIX
+ #define LINK_EMUL_PREFIX "shlsymbian"
+ 
+ 
+ #define SYMBIAN_EXPORT_NAME(NAME,FILE,DECL)			\
+   do								\
+     {								\
+       if ((DECL && sh_symbian_dllexport_p (DECL))		\
+          || sh_symbian_dllexport_name_p (NAME))			\
+         {							\
+           fprintf ((FILE), "\t.pushsection .directive\n");	\
+           fprintf ((FILE), "\t.asciz \"EXPORT %s\\n\"\n",	\
+ 	           sh_symbian_strip_name_encoding (NAME));	\
+           fprintf ((FILE), "\t.popsection\n");			\
+        }							\
+     }								\
+   while (0)
+ 
+ /* Output a function definition label.  */
+ #undef  ASM_DECLARE_FUNCTION_NAME
+ #define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL)		\
+   do								\
+     {								\
+       SYMBIAN_EXPORT_NAME ((NAME), (FILE), (DECL));		\
+       ASM_OUTPUT_TYPE_DIRECTIVE ((FILE), (NAME), "function");	\
+       ASM_DECLARE_RESULT ((FILE), DECL_RESULT (DECL));		\
+       ASM_OUTPUT_LABEL ((FILE), (NAME));			\
+     }								\
+   while (0)
+ 
+ /* Output the label for an initialized variable.  */
+ #undef  ASM_DECLARE_OBJECT_NAME
+ #define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL)		\
+   do								\
+     {								\
+       HOST_WIDE_INT size;					\
+ 								\
+       SYMBIAN_EXPORT_NAME ((NAME), (FILE), (DECL));		\
+       ASM_OUTPUT_TYPE_DIRECTIVE ((FILE), (NAME), "object");	\
+ 								\
+       size_directive_output = 0;				\
+       if (!flag_inhibit_size_directive				\
+ 	  && (DECL)						\
+           && DECL_SIZE (DECL))					\
+ 	{							\
+ 	  size_directive_output = 1;				\
+ 	  size = int_size_in_bytes (TREE_TYPE (DECL));		\
+ 	  ASM_OUTPUT_SIZE_DIRECTIVE ((FILE), (NAME), size);	\
+ 	}							\
+ 								\
+       ASM_OUTPUT_LABEL ((FILE), (NAME));			\
+     }								\
+   while (0)
+ 
+ #undef  ASM_OUTPUT_LABELREF
+ #define ASM_OUTPUT_LABELREF(FILE, NAME)				\
+   do								\
+     {								\
+       asm_fprintf ((FILE), "%U%s",				\
+ 		   sh_symbian_strip_name_encoding (NAME));	\
+     }								\
+   while (0)
*** /dev/null	2004-02-18 15:26:44.000000000 +0000
--- config/sh/symbian-pre.h	2004-07-02 13:00:33.000000000 +0100
***************
*** 0 ****
--- 1,48 ----
+ /* Definitions for the Symbian OS running on an SH part.
+    This file is included before any other target specific headers.
+ 
+    Copyright (C) 2004 Free Software Foundation, Inc.
+    Contributed by Red Hat.
+ 
+    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 2, 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 COPYING.  If not, write to the
+    Free Software Foundation, 59 Temple Place - Suite 330,
+    Boston, MA 02111-1307, USA.  */
+ 
+ /* Enable Symbian specific code.  */
+ #define SYMBIAN		1
+ 
+ /* Default to using the Renesas ABI.  */
+ #define TARGET_ABI_DEFAULT	RENESAS_BIT
+ 
+ /* Support the __declspec keyword by turning them into attributes.
+    We currently only support: naked, dllimport, and dllexport.
+    Note that the current way we do this may result in a collision with
+    predefined attributes later on.  This can be solved by using one attribute,
+    say __declspec__, and passing args to it.  The problem with that approach
+    is that args are not accumulated: each new appearance would clobber any
+    existing args.  */
+ #define SUBTARGET_CPP_SPEC "-D__declspec(x)=__attribute__((x))"
+ 
+ /* Get tree.c to declare merge_dllimport_decl_attributes().  */
+ #define TARGET_DLLIMPORT_DECL_ATTRIBUTES
+ 
+ /* The Symbian OS currently does not support exception handling.  */
+ #define SUBTARGET_CC1PLUS_SPEC "-fno-exceptions"
+ 
+ /* Create constructor/destructor sections without the writable flag.
+    Symbian puts them into the text segment and munges them later on.  */
+ #define CTORS_SECTION_ASM_OP	"\t.section\t.ctors,\"ax\",@progbits"
+ #define DTORS_SECTION_ASM_OP	"\t.section\t.dtors,\"ax\",@progbits"
*** /dev/null	2004-02-18 15:26:44.000000000 +0000
--- config/sh/t-symbian	2004-07-02 12:40:10.000000000 +0100
***************
*** 0 ****
--- 1,35 ----
+ LIB1ASMSRC = sh/lib1funcs.asm
+ LIB1ASMFUNCS = _ashiftrt _ashiftrt_n _ashiftlt _lshiftrt _movstr \
+   _movstr_i4 _mulsi3 _sdivsi3 _sdivsi3_i4 _udivsi3 _udivsi3_i4 _set_fpscr \
+   $(LIB1ASMFUNCS_CACHE)
+ 
+ # We want fine grained libraries, so use the new code to build the
+ # floating point emulation libraries.
+ FPBIT = fp-bit.c
+ DPBIT = dp-bit.c
+ 
+ dp-bit.c: $(srcdir)/config/fp-bit.c
+ 	cat $(srcdir)/config/fp-bit.c >> dp-bit.c
+ 
+ fp-bit.c: $(srcdir)/config/fp-bit.c
+ 	echo '#define FLOAT' > fp-bit.c
+ 	cat $(srcdir)/config/fp-bit.c >> fp-bit.c
+ 
+ $(T)crt1.o: $(srcdir)/config/sh/crt1.asm $(GCC_PASSES)
+ 	$(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $(T)crt1.o -x assembler-with-cpp $(srcdir)/config/sh/crt1.asm
+ $(T)crti.o: $(srcdir)/config/sh/crti.asm $(GCC_PASSES)
+ 	$(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $(T)crti.o -x assembler-with-cpp $(srcdir)/config/sh/crti.asm
+ $(T)crtn.o: $(srcdir)/config/sh/crtn.asm $(GCC_PASSES)
+ 	$(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $(T)crtn.o -x assembler-with-cpp $(srcdir)/config/sh/crtn.asm
+ 
+ $(out_object_file): gt-sh.h
+ gt-sh.h : s-gtype ; @true
+ 
+ symbian.o: $(srcdir)/config/sh/symbian.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
+   $(RTL_H) output.h flags.h $(TREE_H) expr.h toplev.h $(TM_P_H)
+ 	$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(srcdir)/config/sh/symbian.c
+ 
+ 
+ # Local Variables:
+ # mode: Makefile
+ # End:
*** /dev/null	2004-02-18 15:26:44.000000000 +0000
--- config/sh/symbian.c	2004-07-06 13:19:42.000000000 +0100
***************
*** 0 ****
--- 1,963 ----
+ /* Routines for GCC for a Symbian OS targeted SH backend.
+    Copyright (C) 2004 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 2, 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 COPYING.  If not, write to
+    the Free Software Foundation, 59 Temple Place - Suite 330,
+    Boston, MA 02111-1307, USA.  */
+ 
+ #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 "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
+ 
+ extern int current_function_anonymous_args;
+ 
+ /* 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."
+ 
+ 
+ /* Return the type that we should use to determine if DECL is
+    imported or exported.  */
+ 
+ static tree
+ sh_symbian_associated_type (tree decl)
+ {
+   tree t = NULL_TREE;
+ 
+   if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
+   /* Methods now inherit their dllimport/dllexport attributes correctly
+      so there is no need to check their class.  In fact it is wrong to
+      check their class since a method can remain unexported from an
+      exported class.  */
+     return t;
+ 
+   /* Otherwise we can just take the DECL_CONTEXT as normal.  */
+   if (DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl)))
+     t = DECL_CONTEXT (decl);
+ 
+   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;
+ }
+ 
+ /* Return nonzero if DECL is a dllimport'd object.  */
+ 
+ static bool
+ sh_symbian_dllimport_p (tree decl)
+ {
+   tree imp;
+ 
+   if (   TREE_CODE (decl) != VAR_DECL
+       && TREE_CODE (decl) != FUNCTION_DECL)
+     return false;
+ 
+   imp = lookup_attribute ("dllimport", DECL_ATTRIBUTES (decl));
+   if (imp)
+     return true;
+ 
+   /* Class members get the dllimport status of their class.  */
+   imp = sh_symbian_associated_type (decl);
+   if (! imp)
+     return false;
+ 
+   imp = lookup_attribute ("dllimport", TYPE_ATTRIBUTES (imp));
+   if (!imp)
+     return false;
+ 
+   /* Don't mark defined functions as dllimport.  If the definition itself
+      was marked with dllimport, then sh_symbian_handle_dll_attribute reports
+      an error. This handles the case when the definition overrides an
+      earlier declaration.  */
+   if (TREE_CODE (decl) ==  FUNCTION_DECL
+       && DECL_INITIAL (decl)
+       && !DECL_INLINE (decl))
+     {
+       /* Don't warn about artificial methods.  */
+       if (!DECL_ARTIFICIAL (decl))
+ 	warning ("%H function '%D' is defined after prior declaration as dllimport: attribute ignored",
+ 		 & DECL_SOURCE_LOCATION (decl), decl);
+       return false;
+     }
+ 
+   /* We ignore the dllimport attribute for inline member functions.
+      This differs from MSVC behavior which treats it like GNUC
+      'extern inline' extension.   */
+   else if (TREE_CODE (decl) == FUNCTION_DECL && DECL_INLINE (decl))
+     {
+       if (extra_warnings)
+ 	warning ("%Hinline function '%D' is declared as dllimport: attribute ignored.",
+ 		 & DECL_SOURCE_LOCATION (decl), decl);
+       return false;
+     }
+ 
+   /*  Don't allow definitions of static data members in dllimport
+       class.  Just ignore the attribute for vtable data.  */
+   else if (TREE_CODE (decl) == VAR_DECL
+ 	   && TREE_STATIC (decl)
+ 	   && TREE_PUBLIC (decl)
+ 	   && !DECL_EXTERNAL (decl))
+     {
+       if (!DECL_VIRTUAL_P (decl))
+ 	error ("%Hdefinition of static data member '%D' of dllimport'd class.",
+ 	       & DECL_SOURCE_LOCATION (decl), decl);
+       return false;
+     }
+ 
+   /* Since we can't treat a pointer to a dllimport'd symbol as a
+      constant address, we turn off the attribute on C++ virtual
+      methods to allow creation of vtables using thunks.  Don't mark
+      artificial methods either (in sh_symbian_associated_type, only
+      COMDAT artificial method get import status from class context).  */
+   else if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE
+ 	   && (DECL_VIRTUAL_P (decl) || DECL_ARTIFICIAL (decl)))
+     return false;
+ 
+   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.  */
+ 
+ 
+ bool
+ sh_symbian_dllimport_name_p (const char *symbol)
+ {
+   return strncmp (DLL_IMPORT_PREFIX, symbol,
+ 		  strlen (DLL_IMPORT_PREFIX)) == 0;
+ }
+ 
+ /* Mark a DECL as being dllexport'd.
+    Note that we override the previous setting (eg: 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 (GET_CODE (rtlname) == SYMBOL_REF)
+     oldname = XSTR (rtlname, 0);
+   else if (GET_CODE (rtlname) == MEM
+ 	   && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF)
+     oldname = XSTR (XEXP (rtlname, 0), 0);
+   else
+     abort ();
+ 
+   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 defintion to be marked as dllexport.  The prototypes
+ 	are in headers used everywhere and the defintion is in a translation
+ 	unit which has included the header in order to ensure argument
+ 	correctness.  */
+       oldname += strlen (DLL_IMPORT_PREFIX);
+       DECL_NON_ADDR_CONST_P (decl) = 0;
+     }
+   else if (sh_symbian_dllexport_name_p (oldname))
+     return; /* Already done.  */
+ 
+   newname = 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));
+ }
+ 
+ /* 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 (GET_CODE (rtlname) == SYMBOL_REF)
+     oldname = XSTR (rtlname, 0);
+   else if (GET_CODE (rtlname) == MEM
+ 	   && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF)
+     oldname = XSTR (XEXP (rtlname, 0), 0);
+   else
+     abort ();
+ 
+   if (sh_symbian_dllexport_name_p (oldname))
+     {
+       error ("`%s' declared as both exported to and imported from a DLL",
+              IDENTIFIER_POINTER (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 ("%Hfailure in redeclaration of '%D': dllimport'd symbol lacks external linkage.",
+ 	       &DECL_SOURCE_LOCATION (decl), 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;
+     }
+ }
+ 
+ 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_NON_ADDR_CONST_P flag.  */
+   else if (  (TREE_CODE (decl) == FUNCTION_DECL
+ 	   || TREE_CODE (decl) == VAR_DECL)
+ 	   && DECL_RTL (decl) != NULL_RTX
+ 	   && GET_CODE (DECL_RTL (decl)) == MEM
+ 	   && GET_CODE (XEXP (DECL_RTL (decl), 0)) == MEM
+ 	   && 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)))
+     {
+       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 ("%H%s '%D' %s after being referenced with dllimport linkage.",
+ 	       & DECL_SOURCE_LOCATION (decl),
+ 	       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_NON_ADDR_CONST_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;
+ }
+ 
+ /* Return nonzero if FUNC is a naked function.  */
+ 
+ bool
+ sh_symbian_naked_function_p (tree func)
+ {
+   tree a;
+ 
+   if (TREE_CODE (func) != FUNCTION_DECL)
+     abort ();
+ 
+   a = lookup_attribute ("naked", DECL_ATTRIBUTES (func));
+   return a != NULL_TREE;
+ }
+ 
+ /* This is part of a nasty hack to suppress the generation of
+    "control reaches end of non-void function" warning messages
+    (eg when ebaled by with -Wall) for naked functions.  */
+ 
+ static int saved_warn_return_type = 0;
+ static int warn_return_type_saved = 0;
+ 
+ /* Handle the naked attribute - make sure that
+    it is only applied to a function decl.  */
+ 
+ tree
+ sh_symbian_handle_naked_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
+ 				   int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+ {
+   if (TREE_CODE (*node) != FUNCTION_DECL)
+     {
+       warning ("`%s' attribute only applies to functions",
+ 	       IDENTIFIER_POINTER (name));
+       *no_add_attrs = true;
+     }
+ 
+   if (! warn_return_type_saved)
+     {
+       saved_warn_return_type = warn_return_type;
+       warn_return_type = 0;
+       warn_return_type_saved = 1;
+     }
+ 
+   return NULL_TREE;
+ }
+ 
+ void
+ sh_symbian_reorg (void)
+ {
+   if (warn_return_type_saved)
+     {
+       warn_return_type = saved_warn_return_type;
+       warn_return_type_saved = 0;
+     }
+ }
+ 
+ /* 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)
+ {
+   tree attrs;
+   tree attr;
+ 
+   attrs = DECL_P (node) ? DECL_ATTRIBUTES (node) : TYPE_ATTRIBUTES (node);
+ 
+   if (lookup_attribute (attr_name, attrs) != NULL_TREE)
+     return;
+ 
+   attr = get_identifier (attr_name);
+ 
+   (DECL_P (node) ? DECL_ATTRIBUTES (node) : TYPE_ATTRIBUTES (node))
+     = tree_cons (attr, NULL_TREE, attrs);
+ 
+ #if SYMBIAN_DEBUG
+   fprintf (stderr, "propogate %s attribute", attr_name);
+   print_node_brief (stderr, " to", node, 0);
+   fprintf (stderr, "\n");
+ #endif
+ }
+ 
+ /* Handle a "dllimport" or "dllexport" attribute;
+    arguments as in struct attribute_spec.handler.  */
+ 
+ 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);
+ 
+   /* 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 ("`%s' 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 ("`%s' 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 ("%Hvariable `%D' definition is marked dllimport.",
+ 		     & DECL_SOURCE_LOCATION (node), 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 desctructor, then we must
+      make sure that the attribute is propogated 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);
+ 
+ 	  /* Propogate 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))
+     {
+       /* Propogate 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);
+     }
+ 
+   /*  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 ("%Hexternal linkage required for symbol '%D' because of '%s' attribute.",
+ 	       & DECL_SOURCE_LOCATION (node), node, IDENTIFIER_POINTER (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;
+ }
+ 
+ /* 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.  */
+ 
+ /* Decide if a base class of a class should
+    also have its vtable and rtti exported.  */
+ 
+ static void
+ symbian_possibly_export_base_class (tree base_class)
+ {
+   tree methods;
+   int len;
+ 
+   if (! (TYPE_POLYMORPHIC_P (base_class)
+ 	 || TYPE_USES_VIRTUAL_BASECLASSES (base_class)))
+     return;
+ 
+   methods = CLASSTYPE_METHOD_VEC (base_class);
+   len = methods ? TREE_VEC_LENGTH (methods) : 0;
+ 
+   for (;len --;)
+     {
+       tree member = TREE_VEC_ELT (methods, len);
+ 
+       if (! member)
+ 	continue;
+ 
+       for (member = OVL_CURRENT (member); member; member = OVL_NEXT (member))
+ 	{
+ 	  if (TREE_CODE (member) != FUNCTION_DECL)
+ 	    continue;
+ 
+ 	  if (DECL_CONSTRUCTOR_P (member) || DECL_DESTRUCTOR_P (member))
+ 	    continue;
+ 
+ 	  if (! DECL_VIRTUAL_P (member))
+ 	    continue;
+ 
+ 	  if (DECL_PURE_VIRTUAL_P (member))
+ 	    continue;
+ 
+ 	  if (DECL_INLINE (member))
+ 	    continue;
+ 
+ 	  break;
+ 	}
+ 
+       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");
+ #endif
+ }
+ 
+ /* Decide if a class needs its vtable and rtti exporting.  */
+ 
+ static bool
+ symbian_export_vtable_and_rtti_p (tree ctype)
+ {
+   bool inline_ctor_dtor;
+   bool dllimport_ctor_dtor;
+   bool dllimport_member;
+   tree binfos;
+   tree methods;
+   tree key;
+   int len;
+ 
+   /* Make sure that we are examining a class...  */
+   if (TREE_CODE (ctype) != RECORD_TYPE)
+     {
+ #if SYMBIAN_DEBUG
+       print_node_brief (stderr, "", ctype, 0);
+       fprintf (stderr, " does NOT need to be EXPORTed [not a class]\n");
+ #endif
+       return false;
+     }
+ 
+   /* If the class does not have a key function it
+      does not need to have its vtable exported.  */
+   if ((key = CLASSTYPE_KEY_METHOD (ctype)) == NULL_TREE)
+     {
+ #if SYMBIAN_DEBUG
+       print_node_brief (stderr, "", ctype, 0);
+       fprintf (stderr, " does NOT need to be EXPORTed [no key function]\n");
+ #endif
+       return false;
+     }
+ 
+   /* If the key fn has not been defined
+      then the class should not be exported.  */
+   if (! TREE_ASM_WRITTEN (key))
+     {
+ #if SYMBIAN_DEBUG
+       print_node_brief (stderr, "", ctype, 0);
+       fprintf (stderr, " does NOT need to be EXPORTed [key function not defined]\n");
+ #endif
+       return false;
+     }
+ 
+   /* Check the class's member functions.  */
+   inline_ctor_dtor = false;
+   dllimport_ctor_dtor = false;
+   dllimport_member = false;
+ 
+   methods = CLASSTYPE_METHOD_VEC (ctype);
+   len = methods ? TREE_VEC_LENGTH (methods) : 0;
+ 
+   for (;len --;)
+     {
+       tree member = TREE_VEC_ELT (methods, len);
+ 
+       if (! member)
+ 	continue;
+ 
+       for (member = OVL_CURRENT (member); member; member = OVL_NEXT (member))
+ 	{
+ 	  if (TREE_CODE (member) != FUNCTION_DECL)
+ 	    continue;
+ 
+ 	  if (DECL_CONSTRUCTOR_P (member) || DECL_DESTRUCTOR_P (member))
+ 	    {
+ 	      if (DECL_INLINE (member)
+ 		  /* Ignore C++ backend created inline ctors/dtors.  */
+ 		  && (   DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (member)
+ 		      || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (member)))
+ 		inline_ctor_dtor = true;
+ 
+ 	      if (lookup_attribute ("dllimport", DECL_ATTRIBUTES (member)))
+ 		dllimport_ctor_dtor = true;
+ 	    }
+ 	  else
+ 	    {
+ 	      if (DECL_PURE_VIRTUAL_P (member))
+ 		continue;
+ 
+ 	      if (! DECL_VIRTUAL_P (member))
+ 		continue;
+ 
+ 	      if (DECL_INLINE (member))
+ 		continue;
+ 
+ 	      if (lookup_attribute ("dllimport", DECL_ATTRIBUTES (member)))
+ 		dllimport_member = true;
+ 	    }
+ 	}
+     }
+ 
+   if (! dllimport_member && ! dllimport_ctor_dtor)
+     {
+ #if SYMBIAN_DEBUG
+       print_node_brief (stderr, "", ctype, 0);
+       fprintf (stderr,
+ 	       " does NOT need to be EXPORTed [no non-pure virtuals or ctors/dtors with dllimport]\n");
+ #endif
+       return false;
+     }
+ 
+   if (! inline_ctor_dtor)
+     {
+ #if SYMBIAN_DEBUG
+       print_node_brief (stderr, "", ctype, 0);
+       fprintf (stderr,
+ 	       " does NOT need to be EXPORTed [no inline ctor/dtor]\n");
+ #endif
+       return false;
+     }
+ 
+ #if SYMBIAN_DEBUG
+   print_node_brief (stderr, "", ctype, 0);
+   fprintf (stderr, " DOES need to be EXPORTed\n");
+ #endif
+ 
+   /* Now we must check and possibly export the base classes.  */
+   binfos = TYPE_BINFO_BASETYPES (ctype);
+   len = CLASSTYPE_N_BASECLASSES (ctype);
+ 
+   for (; len --;)
+     {
+       tree base_binfo;
+       tree basetype;
+ 
+       /* Figure out which base we're looking at.  */
+       base_binfo = TREE_VEC_ELT (binfos, len);
+       basetype = TREE_TYPE (base_binfo);
+ 
+       symbian_possibly_export_base_class (basetype);
+     }
+ 
+   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)
+ {
+   /* If the key function has the attribute then the class needs it too.  */
+   if (TYPE_POLYMORPHIC_P (ctype)
+       && CLASSTYPE_KEY_METHOD (ctype)
+       && lookup_attribute (attribute_name,
+ 			   DECL_ATTRIBUTES (CLASSTYPE_KEY_METHOD (ctype))))
+     return true;
+ 
+   /* Check the class's member functions.  */
+   if (TREE_CODE (ctype) == RECORD_TYPE)
+     {
+       tree methods = CLASSTYPE_METHOD_VEC (ctype);
+       unsigned int len = methods ? TREE_VEC_LENGTH (methods) : 0;
+ 
+       for (;len --;)
+ 	{
+ 	  tree member = TREE_VEC_ELT (methods, 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;
+ }
+ 
+ int
+ symbian_import_export_class (tree ctype, int import_export)
+ {
+   const char *attr_name = NULL;
+ 
+   /* If we are exporting the class but it does not have the dllexport
+      attribute then we may need to add it.  Similarly imported classes
+      may need the dllimport attribute.  */
+   switch (import_export)
+     {
+     case  1: attr_name = "dllexport"; break;
+     case -1: attr_name = "dllimport"; break;
+     default: break;
+     }
+ 
+   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);
+ 
+       /* 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");
+ 
+ 	  /* Make sure that the class and its vtable are exported.  */
+ 	  import_export = 1;
+ 
+ 	  if (CLASSTYPE_VTABLES (ctype))
+ 	    DECL_EXTERNAL (CLASSTYPE_VTABLES (ctype)) = 1;
+ 
+ 	  /* Check to make sure that if the class has a key method that
+ 	     it is now on the list of keyed classes.  That way its vtable
+ 	     will be emitted.  */
+ 	  if (CLASSTYPE_KEY_METHOD (ctype))
+ 	    {
+ 	      tree class;
+ 
+ 	      for (class = keyed_classes; class; class = TREE_CHAIN (class))
+ 		if (class == ctype)
+ 		  break;
+ 
+ 	      if (class == NULL_TREE)
+ 		{
+ #if SYMBIAN_DEBUG
+ 		  print_node_brief (stderr, "Add node", ctype, 0);
+ 		  fprintf (stderr, " to the keyed classes list\n");
+ #endif
+ 		  keyed_classes = tree_cons (NULL_TREE, ctype, keyed_classes);
+ 		}
+ 	    }
+ 
+ 	  /* Make sure that the typeinfo will be emitted as well.  */
+ 	  if (CLASS_TYPE_P (ctype))
+ 	    TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (ctype)))) = 1;
+ 	}
+     }
+ 
+   return import_export;
+ }
+ 
+ /* Dummy defintion of this array for cc1 building purposes.  */
+ tree cp_global_trees[CPTI_MAX] __attribute__((weak));
+ 
+ #if defined ENABLE_TREE_CHECKING && (GCC_VERSION >= 2007)
+ 
+ /* Dummy version of this G++ function for building cc1.  */
+ void lang_check_failed (const char *, int, const char *) __attribute__((weak));
+ 
+ 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);
+ }
+ #endif /* ENABLE_TREE_CHECKING */

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]