1/* Target support for C++ classes on Windows.
2   Contributed by Danny Smith (dannysmith@users.sourceforge.net)
3   Copyright (C) 2005-2020 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#define IN_TARGET_CODE 1
22
23#include "config.h"
24#include "system.h"
25#include "coretypes.h"
26#include "cp/cp-tree.h" /* This is why we're a separate module.  */
27#include "stringpool.h"
28#include "attribs.h"
29
30bool
31i386_pe_type_dllimport_p (tree decl)
32{
33  gcc_assert (TREE_CODE (decl) == VAR_DECL
34	      || TREE_CODE (decl) == FUNCTION_DECL);
35
36  if (TARGET_NOP_FUN_DLLIMPORT && TREE_CODE (decl) == FUNCTION_DECL)
37    return false;
38
39  /* We ignore the dllimport attribute for inline member functions.
40     This differs from MSVC behavior which treats it like GNUC
41     'extern inline' extension.  Also ignore for template
42     instantiations with linkonce semantics and artificial methods.  */
43  if (TREE_CODE (decl) ==  FUNCTION_DECL
44      && (DECL_DECLARED_INLINE_P (decl)
45	  || DECL_TEMPLATE_INSTANTIATION (decl)
46	  || DECL_ARTIFICIAL (decl)))
47    return false;
48
49  /* Overrides of the class dllimport decls by out-of-class definitions are
50     handled by tree.c:merge_dllimport_decl_attributes.   */
51  return true;
52}
53
54bool
55i386_pe_type_dllexport_p (tree decl)
56{
57  gcc_assert (TREE_CODE (decl) == VAR_DECL
58              || TREE_CODE (decl) == FUNCTION_DECL);
59
60  /* Avoid exporting compiler-generated default dtors and copy ctors.
61     The only artificial methods that need to be exported are virtual
62     and non-virtual thunks.  */
63  if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE
64      && DECL_ARTIFICIAL (decl) && !DECL_THUNK_P (decl))
65    return false;
66  if (TREE_CODE (decl) == FUNCTION_DECL
67      && DECL_DECLARED_INLINE_P (decl))
68    {
69      if (DECL_REALLY_EXTERN (decl)
70	  || !flag_keep_inline_dllexport)
71	return false;
72    }
73  return true;
74}
75
76static inline void maybe_add_dllimport (tree decl)
77{
78  if (i386_pe_type_dllimport_p (decl))
79    DECL_DLLIMPORT_P (decl) = 1;
80}
81
82static inline void maybe_add_dllexport (tree decl)
83{
84  if (i386_pe_type_dllexport_p (decl))
85    {
86      tree decl_attrs = DECL_ATTRIBUTES (decl);
87      if (lookup_attribute ("dllexport", decl_attrs) != NULL_TREE)
88	/* Already done.  */
89	return;
90      DECL_ATTRIBUTES (decl) = tree_cons (get_identifier ("dllexport"),
91					  NULL_TREE, decl_attrs);
92    }
93}
94
95void
96i386_pe_adjust_class_at_definition (tree t)
97{
98  tree member;
99
100  gcc_assert (CLASS_TYPE_P (t));
101
102
103  if (lookup_attribute ("dllexport", TYPE_ATTRIBUTES (t)) != NULL_TREE)
104    {
105      tree tmv = TYPE_MAIN_VARIANT (t);
106
107      /* Make sure that we set dllexport attribute to typeinfo's
108	 base declaration, as otherwise it would fail to be exported as
109	 it isn't a class-member.  */
110      if (tmv != NULL_TREE
111	  && CLASSTYPE_TYPEINFO_VAR (tmv) != NULL_TREE)
112	{
113	  tree na, ti_decl = CLASSTYPE_TYPEINFO_VAR (tmv);
114	  na = tree_cons (get_identifier ("dllexport"), NULL_TREE,
115			  NULL_TREE);
116	  decl_attributes (&ti_decl, na, 0);
117	}
118
119      /* Check FUNCTION_DECL's and static VAR_DECL's.  */
120      for (member = TYPE_FIELDS (t); member; member = DECL_CHAIN (member))
121	if (TREE_CODE (member) == VAR_DECL)
122	  maybe_add_dllexport (member);
123	else if (TREE_CODE (member) == FUNCTION_DECL)
124	  {
125	    tree thunk;
126	    maybe_add_dllexport (member);
127
128	    /* Also add the attribute to its thunks.  */
129	    for (thunk = DECL_THUNKS (member); thunk;
130		 thunk = TREE_CHAIN (thunk))
131	      maybe_add_dllexport (thunk);
132	  }
133
134      /* Check vtables  */
135      for (member = CLASSTYPE_VTABLES (t);
136	   member; member = DECL_CHAIN (member))
137	if (TREE_CODE (member) == VAR_DECL)
138	  maybe_add_dllexport (member);
139    }
140
141  else if (lookup_attribute ("dllimport", TYPE_ATTRIBUTES (t)) != NULL_TREE)
142    {
143      /* We don't actually add the attribute to the decl, just set the flag
144	 that signals that the address of this symbol is not a compile-time
145	 constant.   Any subsequent out-of-class declaration of members wil
146	 cause the DECL_DLLIMPORT_P flag to be unset.
147	 (See  tree.c: merge_dllimport_decl_attributes).
148	 That is just right since out-of class declarations can only be a
149	 definition.   */
150
151      /* Check FUNCTION_DECL's and static VAR_DECL's.  */
152      for (member = TYPE_FIELDS (t); member; member = DECL_CHAIN (member))
153	if (TREE_CODE (member) == VAR_DECL)
154	  maybe_add_dllimport (member);
155	else if (TREE_CODE (member) == FUNCTION_DECL)
156	  {
157	    tree thunk;
158	    maybe_add_dllimport (member);
159
160	    /* Also add the attribute to its thunks.  */
161	    for (thunk = DECL_THUNKS (member); thunk;
162		 thunk = DECL_CHAIN (thunk))
163	      maybe_add_dllimport (thunk);
164	  }
165
166      /* Check vtables  */
167      for (member = CLASSTYPE_VTABLES (t);
168	   member;  member = DECL_CHAIN (member))
169	if (TREE_CODE (member) == VAR_DECL)
170	  maybe_add_dllimport (member);
171
172      /* We leave typeinfo tables alone.  We can't mark TI objects as
173	dllimport, since the address of a secondary VTT may be needed
174	for static initialization of a primary VTT.  VTT's  of
175	dllimport'd classes should always be link-once COMDAT.  */
176    }
177}
178