| /* Target support for C++ classes on Windows. |
| Contributed by Danny Smith (dannysmith@users.sourceforge.net) |
| Copyright (C) 2005-2021 Free Software Foundation, Inc. |
| |
| 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 3, 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 COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| #define IN_TARGET_CODE 1 |
| |
| #include "config.h" |
| #include "system.h" |
| #include "coretypes.h" |
| #include "cp/cp-tree.h" /* This is why we're a separate module. */ |
| #include "stringpool.h" |
| #include "attribs.h" |
| |
| bool |
| i386_pe_type_dllimport_p (tree decl) |
| { |
| gcc_assert (TREE_CODE (decl) == VAR_DECL |
| || TREE_CODE (decl) == FUNCTION_DECL); |
| |
| if (TARGET_NOP_FUN_DLLIMPORT && TREE_CODE (decl) == FUNCTION_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. Also ignore for template |
| instantiations with linkonce semantics and artificial methods. */ |
| if (TREE_CODE (decl) == FUNCTION_DECL |
| && (DECL_DECLARED_INLINE_P (decl) |
| || DECL_TEMPLATE_INSTANTIATION (decl) |
| || DECL_ARTIFICIAL (decl))) |
| return false; |
| |
| /* Overrides of the class dllimport decls by out-of-class definitions are |
| handled by tree.c:merge_dllimport_decl_attributes. */ |
| return true; |
| } |
| |
| bool |
| i386_pe_type_dllexport_p (tree decl) |
| { |
| gcc_assert (TREE_CODE (decl) == VAR_DECL |
| || TREE_CODE (decl) == FUNCTION_DECL); |
| |
| /* Avoid exporting compiler-generated default dtors and copy ctors. |
| The only artificial methods that need to be exported are virtual |
| and non-virtual thunks. */ |
| if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE |
| && DECL_ARTIFICIAL (decl) && !DECL_THUNK_P (decl)) |
| return false; |
| if (TREE_CODE (decl) == FUNCTION_DECL |
| && DECL_DECLARED_INLINE_P (decl)) |
| { |
| if (DECL_REALLY_EXTERN (decl) |
| || !flag_keep_inline_dllexport) |
| return false; |
| } |
| return true; |
| } |
| |
| static inline void maybe_add_dllimport (tree decl) |
| { |
| if (i386_pe_type_dllimport_p (decl)) |
| DECL_DLLIMPORT_P (decl) = 1; |
| } |
| |
| static inline void maybe_add_dllexport (tree decl) |
| { |
| if (i386_pe_type_dllexport_p (decl)) |
| { |
| tree decl_attrs = DECL_ATTRIBUTES (decl); |
| if (lookup_attribute ("dllexport", decl_attrs) != NULL_TREE) |
| /* Already done. */ |
| return; |
| DECL_ATTRIBUTES (decl) = tree_cons (get_identifier ("dllexport"), |
| NULL_TREE, decl_attrs); |
| } |
| } |
| |
| void |
| i386_pe_adjust_class_at_definition (tree t) |
| { |
| tree member; |
| |
| gcc_assert (CLASS_TYPE_P (t)); |
| |
| |
| if (lookup_attribute ("dllexport", TYPE_ATTRIBUTES (t)) != NULL_TREE) |
| { |
| tree tmv = TYPE_MAIN_VARIANT (t); |
| |
| /* Make sure that we set dllexport attribute to typeinfo's |
| base declaration, as otherwise it would fail to be exported as |
| it isn't a class-member. */ |
| if (tmv != NULL_TREE |
| && CLASSTYPE_TYPEINFO_VAR (tmv) != NULL_TREE) |
| { |
| tree na, ti_decl = CLASSTYPE_TYPEINFO_VAR (tmv); |
| na = tree_cons (get_identifier ("dllexport"), NULL_TREE, |
| NULL_TREE); |
| decl_attributes (&ti_decl, na, 0); |
| } |
| |
| /* Check FUNCTION_DECL's and static VAR_DECL's. */ |
| for (member = TYPE_FIELDS (t); member; member = DECL_CHAIN (member)) |
| if (TREE_CODE (member) == VAR_DECL) |
| maybe_add_dllexport (member); |
| else if (TREE_CODE (member) == FUNCTION_DECL) |
| { |
| tree thunk; |
| maybe_add_dllexport (member); |
| |
| /* Also add the attribute to its thunks. */ |
| for (thunk = DECL_THUNKS (member); thunk; |
| thunk = TREE_CHAIN (thunk)) |
| maybe_add_dllexport (thunk); |
| } |
| |
| /* Check vtables */ |
| for (member = CLASSTYPE_VTABLES (t); |
| member; member = DECL_CHAIN (member)) |
| if (TREE_CODE (member) == VAR_DECL) |
| maybe_add_dllexport (member); |
| } |
| |
| else if (lookup_attribute ("dllimport", TYPE_ATTRIBUTES (t)) != NULL_TREE) |
| { |
| /* We don't actually add the attribute to the decl, just set the flag |
| that signals that the address of this symbol is not a compile-time |
| constant. Any subsequent out-of-class declaration of members wil |
| cause the DECL_DLLIMPORT_P flag to be unset. |
| (See tree.c: merge_dllimport_decl_attributes). |
| That is just right since out-of class declarations can only be a |
| definition. */ |
| |
| /* Check FUNCTION_DECL's and static VAR_DECL's. */ |
| for (member = TYPE_FIELDS (t); member; member = DECL_CHAIN (member)) |
| if (TREE_CODE (member) == VAR_DECL) |
| maybe_add_dllimport (member); |
| else if (TREE_CODE (member) == FUNCTION_DECL) |
| { |
| tree thunk; |
| maybe_add_dllimport (member); |
| |
| /* Also add the attribute to its thunks. */ |
| for (thunk = DECL_THUNKS (member); thunk; |
| thunk = DECL_CHAIN (thunk)) |
| maybe_add_dllimport (thunk); |
| } |
| |
| /* Check vtables */ |
| for (member = CLASSTYPE_VTABLES (t); |
| member; member = DECL_CHAIN (member)) |
| if (TREE_CODE (member) == VAR_DECL) |
| maybe_add_dllimport (member); |
| |
| /* We leave typeinfo tables alone. We can't mark TI objects as |
| dllimport, since the address of a secondary VTT may be needed |
| for static initialization of a primary VTT. VTT's of |
| dllimport'd classes should always be link-once COMDAT. */ |
| } |
| } |