1/* Routines for C compiler part of GCC for a Symbian OS targeted SH backend.
2   Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
3   Contributed by RedHat.
4   Most of this code is stolen from i386/winnt.c.
5
6   This file is part of GCC.
7
8   GCC is free software; you can redistribute it and/or modify it
9   under the terms of the GNU General Public License as published
10   by the Free Software Foundation; either version 3, or (at your
11   option) any later version.
12
13   GCC is distributed in the hope that it will be useful, but WITHOUT
14   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
16   License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with GCC; see the file COPYING3.  If not see
20   <http://www.gnu.org/licenses/>.  */
21
22#include "config.h"
23#include "system.h"
24#include "coretypes.h"
25#include "tm.h"
26#include "rtl.h"
27#include "output.h"
28#include "flags.h"
29#include "tree.h"
30#include "expr.h"
31#include "tm_p.h"
32#include "toplev.h"
33#include "sh-symbian.h"
34
35
36/* Return the type that we should use to determine if DECL is
37   imported or exported.  */
38
39tree
40sh_symbian_associated_type (tree decl)
41{
42  tree t = NULL_TREE;
43
44  /* We can just take the DECL_CONTEXT as normal.  */
45  if (DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl)))
46    t = DECL_CONTEXT (decl);
47
48  return t;
49}
50
51/* Return nonzero if DECL is a dllimport'd object.  */
52
53bool
54sh_symbian_is_dllimported (tree decl)
55{
56  tree imp;
57
58  if (   TREE_CODE (decl) != VAR_DECL
59      && TREE_CODE (decl) != FUNCTION_DECL)
60    return false;
61
62  imp = lookup_attribute ("dllimport", DECL_ATTRIBUTES (decl));
63  if (imp)
64    return true;
65
66  /* Class members get the dllimport status of their class.  */
67  imp = sh_symbian_associated_type (decl);
68  if (! imp)
69    return false;
70
71  imp = lookup_attribute ("dllimport", TYPE_ATTRIBUTES (imp));
72  if (!imp)
73    return false;
74
75  /* Don't mark defined functions as dllimport.  If the definition itself
76     was marked with dllimport, then sh_symbian_handle_dll_attribute reports
77     an error. This handles the case when the definition overrides an
78     earlier declaration.  */
79  if (TREE_CODE (decl) ==  FUNCTION_DECL
80      && DECL_INITIAL (decl)
81      && ! DECL_DECLARED_INLINE_P (decl))
82    {
83      warning (OPT_Wattributes, "function %q+D is defined after prior "
84	       "declaration as dllimport: attribute ignored",
85	       decl);
86      return false;
87    }
88
89  /*  Don't allow definitions of static data members in dllimport
90      class.  Just ignore the attribute for vtable data.  */
91  else if (TREE_CODE (decl) == VAR_DECL
92	   && TREE_STATIC (decl)
93	   && TREE_PUBLIC (decl)
94	   && !DECL_EXTERNAL (decl))
95    {
96      error ("definition of static data member %q+D of dllimport'd class",
97	     decl);
98      return false;
99    }
100
101  return true;
102}
103
104/* Handle a "dllimport" or "dllexport" attribute;
105   arguments as in struct attribute_spec.handler.  */
106
107tree
108sh_symbian_handle_dll_attribute (tree *pnode, tree name, tree args,
109				 int flags, bool *no_add_attrs)
110{
111  tree node = *pnode;
112  const char *attr = IDENTIFIER_POINTER (name);
113
114  /* These attributes may apply to structure and union types being
115     created, but otherwise should pass to the declaration involved.  */
116  if (!DECL_P (node))
117    {
118      if (flags & ((int) ATTR_FLAG_DECL_NEXT
119		   | (int) ATTR_FLAG_FUNCTION_NEXT
120		   | (int) ATTR_FLAG_ARRAY_NEXT))
121	{
122	  warning (OPT_Wattributes, "%qs attribute ignored", attr);
123	  *no_add_attrs = true;
124	  return tree_cons (name, args, NULL_TREE);
125	}
126
127      if (TREE_CODE (node) != RECORD_TYPE && TREE_CODE (node) != UNION_TYPE)
128	{
129	  warning (OPT_Wattributes, "%qs attribute ignored", attr);
130	  *no_add_attrs = true;
131	}
132
133      return NULL_TREE;
134    }
135
136  /* Report error on dllimport ambiguities
137     seen now before they cause any damage.  */
138  else if (is_attribute_p ("dllimport", name))
139    {
140      if (TREE_CODE (node) == VAR_DECL)
141	{
142	  if (DECL_INITIAL (node))
143	    {
144	      error ("variable %q+D definition is marked dllimport",
145		     node);
146	      *no_add_attrs = true;
147	    }
148
149	  /* `extern' needn't be specified with dllimport.
150	     Specify `extern' now and hope for the best.  Sigh.  */
151	  DECL_EXTERNAL (node) = 1;
152	  /* Also, implicitly give dllimport'd variables declared within
153	     a function global scope, unless declared static.  */
154	  if (current_function_decl != NULL_TREE && ! TREE_STATIC (node))
155  	    TREE_PUBLIC (node) = 1;
156	}
157    }
158
159  /*  Report error if symbol is not accessible at global scope.  */
160  if (!TREE_PUBLIC (node)
161      && (   TREE_CODE (node) == VAR_DECL
162	  || TREE_CODE (node) == FUNCTION_DECL))
163    {
164      error ("external linkage required for symbol %q+D because of %qE attribute",
165	     node, name);
166      *no_add_attrs = true;
167    }
168
169#if SYMBIAN_DEBUG
170  print_node_brief (stderr, "mark node", node, 0);
171  fprintf (stderr, " as %s\n", attr);
172#endif
173
174  return NULL_TREE;
175}
176
177int
178sh_symbian_import_export_class (tree ctype ATTRIBUTE_UNUSED, int import_export)
179{
180  return import_export;
181}
182