1/* Target support for C++ classes on Windows.
2   Contributed by Danny Smith (dannysmith@users.sourceforge.net)
3   Copyright (C) 2005-2015 Free Software Foundation, Inc.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3.  If not see
19<http://www.gnu.org/licenses/>.  */
20
21#include "config.h"
22#include "system.h"
23#include "coretypes.h"
24#include "tm.h"
25#include "hash-set.h"
26#include "machmode.h"
27#include "vec.h"
28#include "double-int.h"
29#include "input.h"
30#include "alias.h"
31#include "symtab.h"
32#include "wide-int.h"
33#include "inchash.h"
34#include "tree.h"
35#include "stringpool.h"
36#include "attribs.h"
37#include "cp/cp-tree.h" /* This is why we're a separate module.  */
38#include "flags.h"
39#include "tm_p.h"
40#include "diagnostic-core.h"
41#include "hashtab.h"
42
43bool
44i386_pe_type_dllimport_p (tree decl)
45{
46  gcc_assert (TREE_CODE (decl) == VAR_DECL
47	      || TREE_CODE (decl) == FUNCTION_DECL);
48
49  if (TARGET_NOP_FUN_DLLIMPORT && TREE_CODE (decl) == FUNCTION_DECL)
50    return false;
51
52  /* We ignore the dllimport attribute for inline member functions.
53     This differs from MSVC behavior which treats it like GNUC
54     'extern inline' extension.  Also ignore for template
55     instantiations with linkonce semantics and artificial methods.  */
56  if (TREE_CODE (decl) ==  FUNCTION_DECL
57      && (DECL_DECLARED_INLINE_P (decl)
58	  || DECL_TEMPLATE_INSTANTIATION (decl)
59	  || DECL_ARTIFICIAL (decl)))
60    return false;
61
62  /* Overrides of the class dllimport decls by out-of-class definitions are
63     handled by tree.c:merge_dllimport_decl_attributes.   */
64  return true;
65}
66
67bool
68i386_pe_type_dllexport_p (tree decl)
69{
70  gcc_assert (TREE_CODE (decl) == VAR_DECL
71              || TREE_CODE (decl) == FUNCTION_DECL);
72
73  /* Avoid exporting compiler-generated default dtors and copy ctors.
74     The only artificial methods that need to be exported are virtual
75     and non-virtual thunks.  */
76  if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE
77      && DECL_ARTIFICIAL (decl) && !DECL_THUNK_P (decl))
78    return false;
79  if (TREE_CODE (decl) == FUNCTION_DECL
80      && DECL_DECLARED_INLINE_P (decl))
81    {
82      if (DECL_REALLY_EXTERN (decl)
83	  || !flag_keep_inline_dllexport)
84	return false;
85    }
86  return true;
87}
88
89static inline void maybe_add_dllimport (tree decl)
90{
91  if (i386_pe_type_dllimport_p (decl))
92    DECL_DLLIMPORT_P (decl) = 1;
93}
94
95static inline void maybe_add_dllexport (tree decl)
96{
97  if (i386_pe_type_dllexport_p (decl))
98    {
99      tree decl_attrs = DECL_ATTRIBUTES (decl);
100      if (lookup_attribute ("dllexport", decl_attrs) != NULL_TREE)
101	/* Already done.  */
102	return;
103      DECL_ATTRIBUTES (decl) = tree_cons (get_identifier ("dllexport"),
104					  NULL_TREE, decl_attrs);
105    }
106}
107
108void
109i386_pe_adjust_class_at_definition (tree t)
110{
111  tree member;
112
113  gcc_assert (CLASS_TYPE_P (t));
114
115
116  if (lookup_attribute ("dllexport", TYPE_ATTRIBUTES (t)) != NULL_TREE)
117    {
118      tree tmv = TYPE_MAIN_VARIANT (t);
119
120      /* Make sure that we set dllexport attribute to typeinfo's
121	 base declaration, as otherwise it would fail to be exported as
122	 it isn't a class-member.  */
123      if (tmv != NULL_TREE
124	  && CLASSTYPE_TYPEINFO_VAR (tmv) != NULL_TREE)
125	{
126	  tree na, ti_decl = CLASSTYPE_TYPEINFO_VAR (tmv);
127	  na = tree_cons (get_identifier ("dllexport"), NULL_TREE,
128			  NULL_TREE);
129	  decl_attributes (&ti_decl, na, 0);
130	}
131
132      /* Check static VAR_DECL's.  */
133      for (member = TYPE_FIELDS (t); member; member = DECL_CHAIN (member))
134	if (TREE_CODE (member) == VAR_DECL)
135	  maybe_add_dllexport (member);
136
137      /* Check FUNCTION_DECL's.  */
138      for (member = TYPE_METHODS (t); member;  member = DECL_CHAIN (member))
139	if (TREE_CODE (member) == FUNCTION_DECL)
140	  {
141	    tree thunk;
142	    maybe_add_dllexport (member);
143
144	    /* Also add the attribute to its thunks.  */
145	    for (thunk = DECL_THUNKS (member); thunk;
146		 thunk = TREE_CHAIN (thunk))
147	      maybe_add_dllexport (thunk);
148	}
149      /* Check vtables  */
150      for (member = CLASSTYPE_VTABLES (t); member;  member = DECL_CHAIN (member))
151	if (TREE_CODE (member) == VAR_DECL)
152	  maybe_add_dllexport (member);
153    }
154
155  else if (lookup_attribute ("dllimport", TYPE_ATTRIBUTES (t)) != NULL_TREE)
156    {
157      /* We don't actually add the attribute to the decl, just set the flag
158	 that signals that the address of this symbol is not a compile-time
159	 constant.   Any subsequent out-of-class declaration of members wil
160	 cause the DECL_DLLIMPORT_P flag to be unset.
161	 (See  tree.c: merge_dllimport_decl_attributes).
162	 That is just right since out-of class declarations can only be a
163	 definition.   */
164
165      /* Check static VAR_DECL's.  */
166      for (member = TYPE_FIELDS (t); member; member = DECL_CHAIN (member))
167	if (TREE_CODE (member) == VAR_DECL)
168	  maybe_add_dllimport (member);
169
170      /* Check FUNCTION_DECL's.  */
171      for (member = TYPE_METHODS (t); member;  member = DECL_CHAIN (member))
172	if (TREE_CODE (member) == FUNCTION_DECL)
173	  {
174	    tree thunk;
175	    maybe_add_dllimport (member);
176
177	    /* Also add the attribute to its thunks.  */
178	    for (thunk = DECL_THUNKS (member); thunk;
179		 thunk = DECL_CHAIN (thunk))
180	      maybe_add_dllimport (thunk);
181	 }
182
183      /* Check vtables  */
184      for (member = CLASSTYPE_VTABLES (t); member;  member = DECL_CHAIN (member))
185	if (TREE_CODE (member) == VAR_DECL)
186	  maybe_add_dllimport (member);
187
188      /* We leave typeinfo tables alone.  We can't mark TI objects as
189	dllimport, since the address of a secondary VTT may be needed
190	for static initialization of a primary VTT.  VTT's  of
191	dllimport'd classes should always be link-once COMDAT.  */
192    }
193}
194