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