From 43d9ad1dbd24f0dbb1ee8fbb8978acc1019a67f8 Mon Sep 17 00:00:00 2001 From: Danny Smith Date: Wed, 12 Oct 2005 20:54:50 +0000 Subject: [PATCH] re PR target/21275 (gcc 4.0.0 crash with mingw when using stdout in global var) PR middle-end/21275 PR middle-end/21766 * target.h (struct gcc_target): Add valid_dllimport_attribute_p target hook. (struct cxx): Add adjust_class_at_definition target hook. * target-def.h: (TARGET_VALID_DLLIMPORT_ATTRIBUTE_P): New define, defaulting to hook_bool_tree_true. Add to TARGET_INITIALIZER (TARGET_CXX_ADJUST_CLASS_AT_DEFINITION): New define, defaulting to hook_void_tree. Add to TARGET_CXX. * tree.h (struct decl_with_vis): Rename non_addr_const_p field to dllimport_flag. (DECL_NON_ADDR_CONSTANT_P): Replace with DECL_DLLIMPORT_P macro. * tree.c (merge_dllimport_decl_attributes): Check DECL_DLLIMPORT_P instead of attribute. Check for dllexport override. Warn if inconsistent dll linkage. Don't lose old dllimport if decl has had address referenced. Tweak lookup of dllimport atribute. (handle_dll_attribute): Check targetm.valid_dllimport_attribute_p for target specific rules. Don't add dllimport attribute if DECL_DECLARED_INLINE_P. Set DECL_DLLIMPORT_P when adding dllimport attribute. (staticp): Replace DECL_NON_ADDR_CONSTANT_P with DECL_DLLIMPORT_P. * varasm.c (initializer_constant_valid_p): Replace DECL_NON_ADDR_CONSTANT_P with DECL_DLLIMPORT_P PR target/21801 PR target/23589 * config.gcc (i[34567]86-*-cygwin*): Add winnt-cxx.o to 'cxx_target_objs', winnt-stubs,o to 'extra_objs'. (i[34567]86-*-mingw32*): Likewise. * doc/tm.texi (TARGET_CXX_ADJUST_CLASS_AT_DEFINITION): Document. (TARGET_VALID_DLLIMPORT_ATTRIBUTE_P): Document. * config/i386/winnt.c (i386_pe_dllimport_p): Factor out C++-specific code. Change return value to bool. (i386_pe_dllimport_p): Likewise. (associated_type): Simplify and make language-independent (i386_pe_encode_section_info): Replace override of ambiguous dllimport symbol refs with a gcc_assert. (i386_pe_valid_dllimport_attribute_p): Define. * config/i386/winnt-cxx.c: New file. Define C++ versions of i386_pe_type_dllimport_p, i386_pe_type_dllexport_p, i386_pe_adjust_class_at_definition. * config/i386/winnt-stubs.c: New file. Define stub versions of lang-specific functions. * config/i386/i386-protos.h: Declare winnt-[cxx|stubs].c functions i386_pe_type_dllimport_p, i386_pe_type_dllexport_p, i386_pe_adjust_class_at_definition. (i386_pe_valid_dllimport_attribute_p): Declare. * config/i386/cygming.h (TARGET_VALID_DLLIMPORT_ATTRIBUTE_P): Define. (TARGET_CXX_ADJUST_CLASS_AT_DEFINITION): Define. * config/i386/t-cygming: Add rules for winnt-cxx.o, winnt-stubs.o. PR target/19704 * config/i386/i386.c (ix86_function_ok_for_sibcall): Replace test for dllimport attribute with test of DECL_DLLIMPORT_P. cp PR target/21801 PR target/23589 * class.c (finish_struct_1): Call targetm.cxx.adjust_class_at_definition. testsuite * gcc.dg/dll-2.c: Add tests for warnings. * gcc.dg/dll-3.c: Likewise. * gcc.dg/dll-4.c: Likewise. * g++.dg/ext/dllimport1.C: Adjust tests for warnings. * g++.dg/ext/dllimport2.C: Likewise. * g++.dg/ext/dllimport3.C: Likewise. * g++.dg/ext/dllimport7.C: Likewise. * g++.dg/ext/dllimport8.C: Likewise. * g++.dg/ext/dllimport9.C: Likewise. From-SVN: r105332 --- gcc/ChangeLog | 59 ++++++++ gcc/config.gcc | 7 +- gcc/config/i386/cygming.h | 3 + gcc/config/i386/i386-protos.h | 7 + gcc/config/i386/i386.c | 2 +- gcc/config/i386/t-cygming | 13 ++ gcc/config/i386/winnt-cxx.c | 166 ++++++++++++++++++++ gcc/config/i386/winnt-stubs.c | 53 +++++++ gcc/config/i386/winnt.c | 208 ++++++++------------------ gcc/cp/ChangeLog | 8 + gcc/cp/class.c | 5 + gcc/doc/tm.texi | 12 ++ gcc/target-def.h | 10 ++ gcc/target.h | 10 ++ gcc/testsuite/ChangeLog | 13 ++ gcc/testsuite/g++.dg/ext/dllimport1.C | 6 +- gcc/testsuite/g++.dg/ext/dllimport2.C | 13 +- gcc/testsuite/g++.dg/ext/dllimport3.C | 21 ++- gcc/testsuite/g++.dg/ext/dllimport7.C | 8 +- gcc/testsuite/g++.dg/ext/dllimport8.C | 20 +-- gcc/testsuite/g++.dg/ext/dllimport9.C | 4 +- gcc/testsuite/gcc.dg/dll-2.c | 9 +- gcc/testsuite/gcc.dg/dll-3.c | 4 +- gcc/testsuite/gcc.dg/dll-4.c | 4 +- gcc/tree.c | 84 ++++++++--- gcc/tree.h | 7 +- gcc/varasm.c | 2 +- 27 files changed, 538 insertions(+), 220 deletions(-) create mode 100755 gcc/config/i386/winnt-cxx.c create mode 100755 gcc/config/i386/winnt-stubs.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f2b9db354b6..18c64b801c3 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,62 @@ +2005-10-12 Danny Smith + + PR middle-end/21275 + PR middle-end/21766 + * target.h (struct gcc_target): Add valid_dllimport_attribute_p + target hook. + (struct cxx): Add adjust_class_at_definition target hook. + * target-def.h: (TARGET_VALID_DLLIMPORT_ATTRIBUTE_P): New define, + defaulting to hook_bool_tree_true. Add to TARGET_INITIALIZER + (TARGET_CXX_ADJUST_CLASS_AT_DEFINITION): New define, defaulting to + hook_void_tree. Add to TARGET_CXX. + * tree.h (struct decl_with_vis): Rename non_addr_const_p field to + dllimport_flag. + (DECL_NON_ADDR_CONSTANT_P): Replace with DECL_DLLIMPORT_P macro. + * tree.c (merge_dllimport_decl_attributes): Check DECL_DLLIMPORT_P + instead of attribute. Check for dllexport override. Warn if + inconsistent dll linkage. Don't lose old dllimport if decl has + had address referenced. Tweak lookup of dllimport atribute. + (handle_dll_attribute): Check targetm.valid_dllimport_attribute_p + for target specific rules. Don't add dllimport attribute if + DECL_DECLARED_INLINE_P. Set DECL_DLLIMPORT_P when adding + dllimport attribute. + (staticp): Replace DECL_NON_ADDR_CONSTANT_P with DECL_DLLIMPORT_P. + * varasm.c (initializer_constant_valid_p): Replace + DECL_NON_ADDR_CONSTANT_P with DECL_DLLIMPORT_P + + PR target/21801 + PR target/23589 + * config.gcc (i[34567]86-*-cygwin*): Add winnt-cxx.o to + 'cxx_target_objs', winnt-stubs,o to 'extra_objs'. + (i[34567]86-*-mingw32*): Likewise. + + * doc/tm.texi (TARGET_CXX_ADJUST_CLASS_AT_DEFINITION): Document. + (TARGET_VALID_DLLIMPORT_ATTRIBUTE_P): Document. + + * config/i386/winnt.c (i386_pe_dllimport_p): Factor out + C++-specific code. Change return value to bool. + (i386_pe_dllimport_p): Likewise. + (associated_type): Simplify and make language-independent + (i386_pe_encode_section_info): Replace override of ambiguous + dllimport symbol refs with a gcc_assert. + (i386_pe_valid_dllimport_attribute_p): Define. + * config/i386/winnt-cxx.c: New file. Define C++ versions of + i386_pe_type_dllimport_p, i386_pe_type_dllexport_p, + i386_pe_adjust_class_at_definition. + * config/i386/winnt-stubs.c: New file. Define stub versions of + lang-specific functions. + * config/i386/i386-protos.h: Declare winnt-[cxx|stubs].c functions + i386_pe_type_dllimport_p, i386_pe_type_dllexport_p, + i386_pe_adjust_class_at_definition. + (i386_pe_valid_dllimport_attribute_p): Declare. + * config/i386/cygming.h (TARGET_VALID_DLLIMPORT_ATTRIBUTE_P): Define. + (TARGET_CXX_ADJUST_CLASS_AT_DEFINITION): Define. + * config/i386/t-cygming: Add rules for winnt-cxx.o, winnt-stubs.o. + + PR target/19704 + * config/i386/i386.c (ix86_function_ok_for_sibcall): Replace test for + dllimport attribute with test of DECL_DLLIMPORT_P. + 2005-10-12 Adrian Straetling * combine.c (make_extraction): Correct offset computation. diff --git a/gcc/config.gcc b/gcc/config.gcc index 9acca827cc8..21c6dab8cd9 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -1202,9 +1202,9 @@ i[34567]86-*-pe | i[34567]86-*-cygwin*) tmake_file="i386/t-cygwin i386/t-cygming" target_gtfiles="\$(srcdir)/config/i386/winnt.c" extra_options="${extra_options} i386/cygming.opt" - extra_objs=winnt.o + extra_objs="winnt.o winnt-stubs.o" c_target_objs=cygwin2.o - cxx_target_objs=cygwin2.o + cxx_target_objs="cygwin2.o winnt-cxx.o" extra_gcc_objs=cygwin1.o if test x$enable_threads = xyes; then thread_file='posix' @@ -1216,7 +1216,8 @@ i[34567]86-*-mingw32*) tmake_file="i386/t-cygming i386/t-mingw32" target_gtfiles="\$(srcdir)/config/i386/winnt.c" extra_options="${extra_options} i386/cygming.opt" - extra_objs=winnt.o + extra_objs="winnt.o winnt-stubs.o" + cxx_target_objs=winnt-cxx.o case ${enable_threads} in "" | yes | win32) thread_file='win32' ;; esac diff --git a/gcc/config/i386/cygming.h b/gcc/config/i386/cygming.h index 4259c1381ff..4005f1d8e63 100644 --- a/gcc/config/i386/cygming.h +++ b/gcc/config/i386/cygming.h @@ -410,6 +410,9 @@ extern int i386_pe_dllimport_name_p (const char *); #undef NO_PROFILE_COUNTERS #define NO_PROFILE_COUNTERS 1 +#define TARGET_VALID_DLLIMPORT_ATTRIBUTE_P i386_pe_valid_dllimport_attribute_p +#define TARGET_CXX_ADJUST_CLASS_AT_DEFINITION i386_pe_adjust_class_at_definition + #undef TREE #ifndef BUFSIZ diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h index 8b34e03ebc7..6c81d4d7e9f 100644 --- a/gcc/config/i386/i386-protos.h +++ b/gcc/config/i386/i386-protos.h @@ -244,6 +244,13 @@ extern void i386_pe_encode_section_info (tree, rtx, int); extern const char *i386_pe_strip_name_encoding (const char *); extern const char *i386_pe_strip_name_encoding_full (const char *); extern void i386_pe_output_labelref (FILE *, const char *); +extern bool i386_pe_valid_dllimport_attribute_p (tree); + +/* In winnt-cxx.c and winnt-stubs.c */ +extern void i386_pe_adjust_class_at_definition (tree); +extern bool i386_pe_type_dllimport_p (tree); +extern bool i386_pe_type_dllexport_p (tree); + extern rtx maybe_get_pool_constant (rtx); extern char internal_label_prefix[16]; diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index fa2957080ef..7b3cf6a9255 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -1982,7 +1982,7 @@ ix86_function_ok_for_sibcall (tree decl, tree exp) #if TARGET_DLLIMPORT_DECL_ATTRIBUTES /* Dllimport'd functions are also called indirectly. */ - if (decl && lookup_attribute ("dllimport", DECL_ATTRIBUTES (decl)) + if (decl && DECL_DLLIMPORT_P (decl) && ix86_function_regparm (TREE_TYPE (decl), NULL) >= 3) return false; #endif diff --git a/gcc/config/i386/t-cygming b/gcc/config/i386/t-cygming index aa6ff61ca03..c001a8b0f61 100644 --- a/gcc/config/i386/t-cygming +++ b/gcc/config/i386/t-cygming @@ -16,4 +16,17 @@ winnt.o: $(srcdir)/config/i386/winnt.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(srcdir)/config/i386/winnt.c +winnt-cxx.o: $(srcdir)/config/i386/winnt-cxx.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(TM_H) $(RTL_H) $(REGS_H) hard-reg-set.h output.h $(TREE_H) flags.h \ + $(TM_P_H) toplev.h $(HASHTAB_H) $(GGC_H) + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/i386/winnt-cxx.c + + +winnt-stubs.o: $(srcdir)/config/i386/winnt-stubs.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(TM_H) $(RTL_H) $(REGS_H) hard-reg-set.h output.h $(TREE_H) flags.h \ + $(TM_P_H) toplev.h $(HASHTAB_H) $(GGC_H) + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/i386/winnt-stubs.c + STMP_FIXINC=stmp-fixinc diff --git a/gcc/config/i386/winnt-cxx.c b/gcc/config/i386/winnt-cxx.c new file mode 100755 index 00000000000..5117bd7c7c6 --- /dev/null +++ b/gcc/config/i386/winnt-cxx.c @@ -0,0 +1,166 @@ +/* Target support for C++ classes on Windows. + Contributed by Danny Smith (dannysmith@users.sourceforge.net) + Copyright (C) 2005 + 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 2, 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 COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "rtl.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "output.h" +#include "tree.h" +#include "cp/cp-tree.h" /* this is why we're a separate module */ +#include "flags.h" +#include "tm_p.h" +#include "toplev.h" +#include "hashtab.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; + + /* Since we can't treat a pointer to a dllimport'd symbol as a + constant address, we turn off the attribute on C++ virtual + methods to allow creation of vtables using thunks. */ + else if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE + && DECL_VIRTUAL_P (decl)) + { + /* Even though we ignore the attribute from the start, warn if we later see + an out-of class definition, as we do for other member functions in + tree.c:merge_dllimport_decl_attributes. If this is the key method, the + definition may affect the import-export status of vtables, depending + on how we handle MULTIPLE_SYMBOL_SPACES in cp/decl2.c. */ + if (DECL_INITIAL (decl)) + { + warning (OPT_Wattributes, "%q+D redeclared without dllimport attribute: " + "previous dllimport ignored", decl); +#ifdef PE_DLL_DEBUG + if (decl == CLASSTYPE_KEY_METHOD (DECL_CONTEXT (decl))) + warning (OPT_Wattributes, "key method %q+D of dllimport'd class defined" + decl); +#endif + } + return false; + } + + /* Don't mark defined functions as dllimport. This code will only be + reached if we see a non-inline function defined out-of-class. */ + else if (TREE_CODE (decl) == FUNCTION_DECL + && (DECL_INITIAL (decl))) + return false; + + /* Don't allow definitions of static data members in dllimport class, + If vtable data is marked as DECL_EXTERNAL, import it; otherwise just + ignore the class attribute. */ + else if (TREE_CODE (decl) == VAR_DECL + && TREE_STATIC (decl) && TREE_PUBLIC (decl) + && !DECL_EXTERNAL (decl)) + { + if (!DECL_VIRTUAL_P (decl)) + error ("definition of static data member %q+D of " + "dllimport'd class", decl); + return false; + } + + 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; + return true; +} + +static inline void maybe_add_dllimport (tree decl) +{ + if (i386_pe_type_dllimport_p (decl)) + DECL_DLLIMPORT_P (decl) = 1; +} + +void +i386_pe_adjust_class_at_definition (tree t) +{ + tree member; + + gcc_assert (CLASS_TYPE_P (t)); + + /* We only look at dllimport. The only thing that dllexport does is + add stuff to a '.drectiv' section at end-of-file, so no need to do + anything for dllexport'd classes until we generate RTL. */ + if (lookup_attribute ("dllimport", TYPE_ATTRIBUTES (t)) == NULL_TREE) + return; + + /* 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. We recheck the class members at RTL generation to + emit warnings if this has happened. Definition of static data member + of dllimport'd class always causes an error (as per MS compiler). + */ + + /* Check static VAR_DECL's. */ + for (member = TYPE_FIELDS (t); member; member = TREE_CHAIN (member)) + if (TREE_CODE (member) == VAR_DECL) + maybe_add_dllimport (member); + + /* Check FUNCTION_DECL's. */ + for (member = TYPE_METHODS (t); member; member = TREE_CHAIN (member)) + maybe_add_dllimport (member); + + /* Check vtables */ + for (member = CLASSTYPE_VTABLES (t); member; member = TREE_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. */ +} diff --git a/gcc/config/i386/winnt-stubs.c b/gcc/config/i386/winnt-stubs.c new file mode 100755 index 00000000000..b373345de9c --- /dev/null +++ b/gcc/config/i386/winnt-stubs.c @@ -0,0 +1,53 @@ +/* Dummy subroutines for language-specific support on Windows. + Contributed by Danny Smith (dannysmith@users.sourceforge.net) + Copyright (C) 2005 + 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 2, 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 COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "rtl.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "output.h" +#include "tree.h" +#include "flags.h" +#include "tm_p.h" +#include "toplev.h" +#include "hashtab.h" + +bool +i386_pe_type_dllimport_p (tree decl ATTRIBUTE_UNUSED) +{ + return false; +} + + +bool +i386_pe_type_dllexport_p (tree decl ATTRIBUTE_UNUSED) +{ + return false; +} + + +void +i386_pe_adjust_class_at_definition (tree t ATTRIBUTE_UNUSED) +{ } diff --git a/gcc/config/i386/winnt.c b/gcc/config/i386/winnt.c index c1c605c6a1c..f8a36ff1ba1 100644 --- a/gcc/config/i386/winnt.c +++ b/gcc/config/i386/winnt.c @@ -48,8 +48,8 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA static tree associated_type (tree); static tree gen_stdcall_or_fastcall_suffix (tree, bool); -static int i386_pe_dllexport_p (tree); -static int i386_pe_dllimport_p (tree); +static bool i386_pe_dllexport_p (tree); +static bool i386_pe_dllimport_p (tree); static void i386_pe_mark_dllexport (tree); static void i386_pe_mark_dllimport (tree); @@ -115,131 +115,63 @@ ix86_handle_selectany_attribute (tree *node, tree name, static tree associated_type (tree decl) { - tree t = NULL_TREE; - - /* In the C++ frontend, DECL_CONTEXT for a method doesn't actually refer - to the containing class. So we look at the 'this' arg. */ - if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE) - { - /* Artificial methods are not affected by the import/export status - of their class unless they are COMDAT. Implicit copy ctor's and - dtor's are not affected by class status but virtual and - non-virtual thunks are. */ - if (!DECL_ARTIFICIAL (decl) || DECL_COMDAT (decl)) - t = TYPE_MAIN_VARIANT - (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl))))); - } - else if (DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl))) - t = DECL_CONTEXT (decl); - - return t; + return (DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl))) + ? DECL_CONTEXT (decl) : NULL_TREE; } -/* Return nonzero if DECL is a dllexport'd object. */ -static int +/* Return true if DECL is a dllexport'd object. */ + +static bool i386_pe_dllexport_p (tree decl) { - tree exp; - if (TREE_CODE (decl) != VAR_DECL - && TREE_CODE (decl) != FUNCTION_DECL) - return 0; - exp = lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl)); - if (exp) - return 1; + && TREE_CODE (decl) != FUNCTION_DECL) + return false; - /* Class members get the dllexport status of their class. */ - if (associated_type (decl)) - { - exp = lookup_attribute ("dllexport", - TYPE_ATTRIBUTES (associated_type (decl))); - if (exp) - return 1; - } + if (lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl))) + return true; - return 0; + /* Also mark class members of exported classes with dllexport. */ + if (associated_type (decl) + && lookup_attribute ("dllexport", + TYPE_ATTRIBUTES (associated_type (decl)))) + return i386_pe_type_dllexport_p (decl); + + return false; } -/* Return nonzero if DECL is a dllimport'd object. */ - -static int +static bool i386_pe_dllimport_p (tree decl) { - tree imp; - int context_imp = 0; - - if (TREE_CODE (decl) == FUNCTION_DECL - && TARGET_NOP_FUN_DLLIMPORT) - return 0; - if (TREE_CODE (decl) != VAR_DECL - && TREE_CODE (decl) != FUNCTION_DECL) - return 0; + && TREE_CODE (decl) != FUNCTION_DECL) + return false; - imp = lookup_attribute ("dllimport", DECL_ATTRIBUTES (decl)); + /* Lookup the attribute rather than rely on the DECL_DLLIMPORT_P flag. + We may need to override an earlier decision. */ + if (lookup_attribute ("dllimport", DECL_ATTRIBUTES (decl))) + return true; - /* Class members get the dllimport status of their class. */ - if (!imp && associated_type (decl)) - { - imp = lookup_attribute ("dllimport", - TYPE_ATTRIBUTES (associated_type (decl))); - if (imp) - context_imp = 1; - } + /* The DECL_DLLIMPORT_P flag was set for decls in the class definition + by targetm.cxx.adjust_class_at_definition. Check again to emit + warnings if the class attribute has been overriden by an + out-of-class definition. */ + if (associated_type (decl) + && lookup_attribute ("dllimport", + TYPE_ATTRIBUTES (associated_type (decl)))) + return i386_pe_type_dllimport_p (decl); - if (imp) - { - /* Don't mark defined functions as dllimport. If the definition - itself was marked with dllimport, than ix86_handle_dll_attribute - reports an error. This handles the case when the definition - overrides an earlier declaration. */ - if (TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl) - && !DECL_INLINE (decl)) - { - /* Don't warn about artificial methods. */ - if (!DECL_ARTIFICIAL (decl)) - warning (0, "function %q+D is defined after prior declaration " - "as dllimport: attribute ignored", decl); - return 0; - } + return false; +} - /* We ignore the dllimport attribute for inline member functions. - This differs from MSVC behavior which treats it like GNUC - 'extern inline' extension. */ - else if (TREE_CODE (decl) == FUNCTION_DECL && DECL_INLINE (decl)) - { - if (extra_warnings) - warning (0, "inline function %q+D is declared as dllimport: " - "attribute ignored", decl); - return 0; - } - - /* Don't allow definitions of static data members in dllimport class, - Just ignore attribute for vtable data. */ - else if (TREE_CODE (decl) == VAR_DECL - && TREE_STATIC (decl) && TREE_PUBLIC (decl) - && !DECL_EXTERNAL (decl) && context_imp) - { - if (!DECL_VIRTUAL_P (decl)) - error ("definition of static data member %q+D of " - "dllimport'd class", decl); - return 0; - } - - /* Since we can't treat a pointer to a dllimport'd symbol as a - constant address, we turn off the attribute on C++ virtual - methods to allow creation of vtables using thunks. Don't mark - artificial methods either (in associated_type, only COMDAT - artificial method get import status from class context). */ - else if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE - && (DECL_VIRTUAL_P (decl) || DECL_ARTIFICIAL (decl))) - return 0; - - return 1; - } - - return 0; +/* Handle the -mno-fun-dllimport target switch. */ +bool +i386_pe_valid_dllimport_attribute_p (tree decl) +{ + if (TARGET_NOP_FUN_DLLIMPORT && TREE_CODE (decl) == FUNCTION_DECL) + return false; + return true; } /* Return nonzero if SYMBOL is marked as being dllexport'd. */ @@ -283,7 +215,6 @@ i386_pe_mark_dllexport (tree decl) decl); /* Remove DLL_IMPORT_PREFIX. */ oldname += strlen (DLL_IMPORT_PREFIX); - DECL_NON_ADDR_CONST_P (decl) = 0; } else if (i386_pe_dllexport_name_p (oldname)) return; /* already done */ @@ -328,7 +259,9 @@ i386_pe_mark_dllimport (tree decl) { /* Already done, but do a sanity check to prevent assembler errors. */ - gcc_assert (DECL_EXTERNAL (decl) && TREE_PUBLIC (decl)); + gcc_assert (DECL_EXTERNAL (decl) && TREE_PUBLIC (decl) + && DECL_DLLIMPORT_P (decl)); + return; } newname = alloca (strlen (DLL_IMPORT_PREFIX) + strlen (oldname) + 1); @@ -345,8 +278,7 @@ i386_pe_mark_dllimport (tree decl) newrtl = gen_rtx_MEM (Pmode,symref); XEXP (DECL_RTL (decl), 0) = newrtl; - /* Can't treat a pointer to this as a constant address */ - DECL_NON_ADDR_CONST_P (decl) = 1; + DECL_DLLIMPORT_P (decl) = 1; } /* Return string which is the former assembler name modified with a @@ -431,45 +363,25 @@ i386_pe_encode_section_info (tree decl, rtx rtl, int first) } /* Mark the decl so we can tell from the rtl whether the object is - dllexport'd or dllimport'd. This also handles dllexport/dllimport - override semantics. */ + dllexport'd or dllimport'd. tree.c: merge_dllimport_decl_attributes + handles dllexport/dllimport override semantics. */ if (i386_pe_dllexport_p (decl)) i386_pe_mark_dllexport (decl); else if (i386_pe_dllimport_p (decl)) i386_pe_mark_dllimport (decl); - /* It might be that DECL has already been marked as dllimport, but a - subsequent definition nullified that. The attribute is gone but - DECL_RTL still has (DLL_IMPORT_PREFIX) prefixed. We need to remove - that. Ditto for the DECL_NON_ADDR_CONST_P flag. */ - else if ((TREE_CODE (decl) == FUNCTION_DECL - || TREE_CODE (decl) == VAR_DECL) - && DECL_RTL (decl) != NULL_RTX - && GET_CODE (DECL_RTL (decl)) == MEM - && GET_CODE (XEXP (DECL_RTL (decl), 0)) == MEM - && GET_CODE (XEXP (XEXP (DECL_RTL (decl), 0), 0)) == SYMBOL_REF - && i386_pe_dllimport_name_p (XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0))) - { - const char *oldname = XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0); - - /* Remove DLL_IMPORT_PREFIX. */ - tree idp = get_identifier (oldname + strlen (DLL_IMPORT_PREFIX)); - rtx symref = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp)); - SYMBOL_REF_DECL (symref) = decl; - XEXP (DECL_RTL (decl), 0) = symref; - DECL_NON_ADDR_CONST_P (decl) = 0; - - /* We previously set TREE_PUBLIC and DECL_EXTERNAL. - We leave these alone for now. */ - - if (DECL_INITIAL (decl) || !DECL_EXTERNAL (decl)) - warning (0, "%q+D defined locally after being " - "referenced with dllimport linkage", decl); - else - warning (OPT_Wattributes, "%q+D redeclared without dllimport " - "attribute after being referenced with dllimport linkage", - decl); - } + /* It might be that DECL has been declared as dllimport, but a + subsequent definition nullified that. Assert that + tree.c: merge_dllimport_decl_attributes has removed the attribute + before the RTL name was marked with the DLL_IMPORT_PREFIX. */ + else + gcc_assert (!((TREE_CODE (decl) == FUNCTION_DECL + || TREE_CODE (decl) == VAR_DECL) + && rtl != NULL_RTX + && GET_CODE (rtl) == MEM + && GET_CODE (XEXP (rtl, 0)) == MEM + && GET_CODE (XEXP (XEXP (rtl, 0), 0)) == SYMBOL_REF + && i386_pe_dllimport_name_p (XSTR (XEXP (XEXP (rtl, 0), 0), 0)))); } /* Strip only the leading encoding, leaving the stdcall suffix and fastcall diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 404c7de9943..cb4ce856bfc 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2005-10-12 Danny Smith + + PR target/21801 + PR target/23589 + * class.c (finish_struct_1): Call + targetm.cxx.adjust_class_at_definition. + + 2005-10-12 Nathan Sidwell PR c++/21592 diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 3f56652f045..dceeffe29c1 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -5028,6 +5028,11 @@ finish_struct_1 (tree t) if (warn_overloaded_virtual) warn_hidden (t); + /* Class layout, assignment of virtual table slots, etc., is now + complete. Give the back end a chance to tweak the visibility of + the class or perform any other required target modifications. */ + targetm.cxx.adjust_class_at_definition (t); + maybe_suppress_debug_info (t); dump_class_hierarchy (t); diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 16b48ff87a4..46d24b6b789 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -8478,6 +8478,12 @@ to perform initial processing of the @samp{dllimport} and @file{i386/i386.c}, for example. @end deftypefn +@deftypefn {Target Hook} bool TARGET_VALID_DLLIMPORT_ATTRIBUTE_P (tree @var{decl}) +@var{decl} is a variable or function with @code{__attribute__((dllimport))} +specified. Use this hook if the target needs to add extra validation +checks to @code{handle_dll_attribute}. +@end deftypefn + @defmac TARGET_DECLSPEC Define this macro to a nonzero value if you want to treat @code{__declspec(X)} as equivalent to @code{__attribute((X))}. By @@ -8657,6 +8663,12 @@ should be used to register static destructors when @option{-fuse-cxa-atexit} is in effect. The default is to return false to use @code{__cxa_atexit}. @end deftypefn +@deftypefn {Target Hook} void TARGET_CXX_ADJUST_CLASS_AT_DEFINITION (tree @var{type}) +@var{type} is a C++ class (i.e., RECORD_TYPE or UNION_TYPE) that has just been +defined. Use this hook to make adjustments to the class (eg, tweak +visibility or perform any other required target modifications). +@end deftypefn + @node Misc @section Miscellaneous Parameters @cindex parameters, miscellaneous diff --git a/gcc/target-def.h b/gcc/target-def.h index e874bb7147b..6dd121d952f 100644 --- a/gcc/target-def.h +++ b/gcc/target-def.h @@ -147,6 +147,10 @@ Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define TARGET_INVALID_WITHIN_DOLOOP default_invalid_within_doloop #endif +#ifndef TARGET_VALID_DLLIMPORT_ATTRIBUTE_P +#define TARGET_VALID_DLLIMPORT_ATTRIBUTE_P hook_bool_tree_true +#endif + #ifndef TARGET_HAVE_TLS #define TARGET_HAVE_TLS false #endif @@ -516,6 +520,10 @@ Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define TARGET_CXX_USE_AEABI_ATEXIT hook_bool_void_false #endif +#ifndef TARGET_CXX_ADJUST_CLASS_AT_DEFINITION +#define TARGET_CXX_ADJUST_CLASS_AT_DEFINITION hook_void_tree +#endif + #define TARGET_CXX \ { \ TARGET_CXX_GUARD_TYPE, \ @@ -528,6 +536,7 @@ Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. TARGET_CXX_DETERMINE_CLASS_DATA_VISIBILITY, \ TARGET_CXX_CLASS_DATA_ALWAYS_COMDAT, \ TARGET_CXX_USE_AEABI_ATEXIT, \ + TARGET_CXX_ADJUST_CLASS_AT_DEFINITION \ } /* The whole shebang. */ @@ -593,6 +602,7 @@ Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. TARGET_STACK_PROTECT_GUARD, \ TARGET_STACK_PROTECT_FAIL, \ TARGET_INVALID_WITHIN_DOLOOP, \ + TARGET_VALID_DLLIMPORT_ATTRIBUTE_P, \ TARGET_CALLS, \ TARGET_INVALID_CONVERSION, \ TARGET_INVALID_UNARY_OP, \ diff --git a/gcc/target.h b/gcc/target.h index 564c333136c..cd850d1a4b5 100644 --- a/gcc/target.h +++ b/gcc/target.h @@ -550,6 +550,11 @@ struct gcc_target /* Returns NULL if target supports the insn within a doloop block, otherwise it returns an error message. */ const char * (*invalid_within_doloop) (rtx); + + /* DECL is a variable or function with __attribute__((dllimport)) + specified. Use this hook if the target needs to add extra validation + checks to handle_dll_attribute (). */ + bool (* valid_dllimport_attribute_p) (tree decl); /* Functions relating to calls - argument passing, returns, etc. */ struct calls { @@ -660,6 +665,11 @@ struct gcc_target /* Returns true if __aeabi_atexit should be used to register static destructors. */ bool (*use_aeabi_atexit) (void); + /* TYPE is a C++ class (i.e., RECORD_TYPE or UNION_TYPE) that + has just been defined. Use this hook to make adjustments to the + class (eg, tweak visibility or perform any other required + target modifications). */ + void (*adjust_class_at_definition) (tree type); } cxx; /* True if unwinding tables should be generated by default. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 99d2dbd3309..18ed822c4f3 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,16 @@ +2005-10-12 Danny Smith + + * gcc.dg/dll-2.c: Add tests for warnings. + * gcc.dg/dll-3.c: Likewise. + * gcc.dg/dll-4.c: Likewise. + + * g++.dg/ext/dllimport1.C: Adjust tests for warnings. + * g++.dg/ext/dllimport2.C: Likewise. + * g++.dg/ext/dllimport3.C: Likewise. + * g++.dg/ext/dllimport7.C: Likewise. + * g++.dg/ext/dllimport8.C: Likewise. + * g++.dg/ext/dllimport9.C: Likewise. + 2005-10-10 Paul Thomas PR fortran/24092 diff --git a/gcc/testsuite/g++.dg/ext/dllimport1.C b/gcc/testsuite/g++.dg/ext/dllimport1.C index 253631276a7..1fb69ed9f5c 100644 --- a/gcc/testsuite/g++.dg/ext/dllimport1.C +++ b/gcc/testsuite/g++.dg/ext/dllimport1.C @@ -5,13 +5,13 @@ class __attribute__((dllimport)) Foo { public: - virtual void dummy_foo_func(void) // { dg-warning "inline function" } + virtual void dummy_foo_func(void) {} - void Foo::dummy_foo_fun2(); + void dummy_foo_fun2(); virtual ~Foo(); // avoid warning }; -void Foo::dummy_foo_fun2() // { dg-warning "defined" } +void Foo::dummy_foo_fun2() // { dg-warning "redeclared without dllimport" } { } diff --git a/gcc/testsuite/g++.dg/ext/dllimport2.C b/gcc/testsuite/g++.dg/ext/dllimport2.C index 7b3f68575de..87a96d8ddee 100644 --- a/gcc/testsuite/g++.dg/ext/dllimport2.C +++ b/gcc/testsuite/g++.dg/ext/dllimport2.C @@ -1,5 +1,4 @@ // { dg-do compile { target i?86-*-cygwin* i?86-*-mingw*} } - // PR c++/9738 Dllimport attribute is overriden by later definition/redeclaration void __attribute__((dllimport)) Bar(void); @@ -7,6 +6,7 @@ void __attribute__((dllimport)) Baz(void); __attribute__((dllimport)) int Biz; __attribute__((dllimport)) int Boz; + void Foo(void) { Bar(); @@ -14,14 +14,13 @@ void Foo(void) Biz++; Boz++; } - -void Bar(void) // { dg-warning "defined" } + +void Baz(void); // { dg-warning "referenced with dll linkage" } +void Bar(void) // { dg-warning "referenced with dll linkage" } { } - -void Baz(void); // { dg-warning "redeclared" } -extern int Biz; // { dg-warning "redeclared" } -int Boz; // { dg-warning "defined" } +extern int Biz; // { dg-warning "referenced with dll linkage" } +int Boz; // { dg-warning "referenced with dll linkage" } void foo() { diff --git a/gcc/testsuite/g++.dg/ext/dllimport3.C b/gcc/testsuite/g++.dg/ext/dllimport3.C index 5a13a509d4f..cd16dfa2505 100644 --- a/gcc/testsuite/g++.dg/ext/dllimport3.C +++ b/gcc/testsuite/g++.dg/ext/dllimport3.C @@ -4,22 +4,21 @@ // redefinition without attribute. struct Foo - { - int a; - }; +{ + int a; +}; __attribute__((dllimport)) struct Foo f; - void Bar(void) - { - void* dummy = &f; - } +void Bar(void) +{ + void* dummy = (void*) &f; +} - struct Foo f; // { dg-warning "defined" } +struct Foo f; // { dg-warning "referenced with dll linkage" } -// Dllimport sets DECL_NON_ADDR_CONST_P to 1, so following +// Dllimport'd symbols do not have a constant address, so following // assignment would require static_initialization_and_destruction // if attribute is retained. - void* dummy = &f; - +void* dummy = &f; diff --git a/gcc/testsuite/g++.dg/ext/dllimport7.C b/gcc/testsuite/g++.dg/ext/dllimport7.C index fa76d3eec8c..9754ada962c 100644 --- a/gcc/testsuite/g++.dg/ext/dllimport7.C +++ b/gcc/testsuite/g++.dg/ext/dllimport7.C @@ -18,8 +18,12 @@ class __declspec(dllimport) Bar static const Baz null_baz; }; -const int Bar::three = 3; // { dg-error "definition of static data" } -const Baz Bar::null_baz; // { dg-error "definition of static data" } +const int Bar::three = 3; // { dg-warning "redeclared without dllimport" } +// { dg-error "definition of static data" "C++ specific error" { target i?86-*-cygwin* i?86-*-mingw* } 21 } + +const Baz Bar::null_baz; // { dg-warning "redeclared without dllimport" } +// { dg-error "definition of static data" "C++ specific error" { target i?86-*-cygwin* i?86-*-mingw* } 24 } + int foo() diff --git a/gcc/testsuite/g++.dg/ext/dllimport8.C b/gcc/testsuite/g++.dg/ext/dllimport8.C index 7bc2b46b702..55326c51866 100644 --- a/gcc/testsuite/g++.dg/ext/dllimport8.C +++ b/gcc/testsuite/g++.dg/ext/dllimport8.C @@ -6,19 +6,19 @@ // { dg-options { -Wall -W } } struct __attribute__((dllimport)) Foo - { - static int static_int; - static void static_func1(); - static void static_func2(); +{ + static int static_int; + static void static_func1(); + static void static_func2(); }; -void Foo::static_func1() // { dg-warning "defined" } - { - } +void Foo::static_func1() // { dg-warning "redeclared without dllimport" } +{ +} -inline void Foo::static_func2() // { dg-warning "inline function" } - { - } +inline void Foo::static_func2() +{ +} void testfoo() { diff --git a/gcc/testsuite/g++.dg/ext/dllimport9.C b/gcc/testsuite/g++.dg/ext/dllimport9.C index edf79efd8d1..8d60bb84d3a 100644 --- a/gcc/testsuite/g++.dg/ext/dllimport9.C +++ b/gcc/testsuite/g++.dg/ext/dllimport9.C @@ -6,11 +6,11 @@ inline __attribute__((dllimport)) void bar() { } // { dg-warning "inline" } struct __attribute__ ((dllimport)) Blah { - void in_blah () { } // { dg-warning "inline" } + void in_blah () { } // Don't warn if member declared inline in class definition. void out_blah (); }; -inline void Blah::out_blah(){ } // { dg-warning "inline" } +inline void Blah::out_blah(){ } // Don't warn for inline override of external declaration void use_inlines() { diff --git a/gcc/testsuite/gcc.dg/dll-2.c b/gcc/testsuite/gcc.dg/dll-2.c index 5c81f4e64a1..3b8b60eee41 100644 --- a/gcc/testsuite/gcc.dg/dll-2.c +++ b/gcc/testsuite/gcc.dg/dll-2.c @@ -11,13 +11,12 @@ /* { dg-require-dll "" } */ __declspec (dllimport) int foo1 (); -__declspec (dllexport) int foo1 (); - +__declspec (dllexport) int foo1 (); /* { dg-warning "previous dllimport ignored" } */ __declspec (dllexport) int foo2 (); -__declspec (dllimport) int foo2 (); +__declspec (dllimport) int foo2 (); /* { dg-warning "dllimport ignored" } */ __declspec (dllimport) int bar1; -__declspec (dllexport) int bar1; +__declspec (dllexport) int bar1; /* { dg-warning "previous dllimport ignored" } */ __declspec (dllexport) int bar2; -__declspec (dllimport) int bar2; +__declspec (dllimport) int bar2; /* { dg-warning "dllimport ignored" } */ diff --git a/gcc/testsuite/gcc.dg/dll-3.c b/gcc/testsuite/gcc.dg/dll-3.c index 2d5517eace6..0a3f7df0988 100644 --- a/gcc/testsuite/gcc.dg/dll-3.c +++ b/gcc/testsuite/gcc.dg/dll-3.c @@ -5,10 +5,10 @@ /* { dg-do compile { target i?86-pc-mingw* } } */ __declspec (dllimport) int foo1 (); -__declspec (dllexport) int foo1 (); +__declspec (dllexport) int foo1 (); /* { dg-warning "previous dllimport ignored" } */ __declspec (dllexport) int foo2 (); -__declspec (dllimport) int foo2 (); +__declspec (dllimport) int foo2 (); /* { dg-warning "dllimport ignored" } */ __declspec (dllexport) int foo1 () { return foo2 (); } __declspec (dllexport) int foo2 () { return foo1 (); } diff --git a/gcc/testsuite/gcc.dg/dll-4.c b/gcc/testsuite/gcc.dg/dll-4.c index 45ed7a11007..9fcc8e9ad2c 100644 --- a/gcc/testsuite/gcc.dg/dll-4.c +++ b/gcc/testsuite/gcc.dg/dll-4.c @@ -3,10 +3,10 @@ /* { dg-do compile { target i?86-pc-mingw* } } */ __declspec (dllimport) int foo1; -int foo1; +int foo1; /* { dg-warning "redeclared without dllimport" } */ __declspec (dllimport) int foo2; -int foo2 = 5; +int foo2 = 5; /* { dg-warning "redeclared without dllimport" } */ int f () { return foo1 + foo2; } diff --git a/gcc/tree.c b/gcc/tree.c index 333c745fc01..946bf90044e 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -1797,7 +1797,7 @@ staticp (tree arg) case VAR_DECL: return ((TREE_STATIC (arg) || DECL_EXTERNAL (arg)) && ! DECL_THREAD_LOCAL_P (arg) - && ! DECL_NON_ADDR_CONST_P (arg) + && ! DECL_DLLIMPORT_P (arg) ? arg : NULL); case CONST_DECL: @@ -3478,31 +3478,66 @@ tree merge_dllimport_decl_attributes (tree old, tree new) { tree a; - int delete_dllimport_p; - - old = DECL_ATTRIBUTES (old); - new = DECL_ATTRIBUTES (new); + int delete_dllimport_p = 1; /* What we need to do here is remove from `old' dllimport if it doesn't appear in `new'. dllimport behaves like extern: if a declaration is marked dllimport and a definition appears later, then the object - is not dllimport'd. */ - if (lookup_attribute ("dllimport", old) != NULL_TREE - && lookup_attribute ("dllimport", new) == NULL_TREE) - delete_dllimport_p = 1; + is not dllimport'd. We also remove a `new' dllimport if the old list + contains dllexport: dllexport always overrides dllimport, regardless + of the order of declaration. */ + if (!VAR_OR_FUNCTION_DECL_P (new)) + delete_dllimport_p = 0; + else if (DECL_DLLIMPORT_P (new) + && lookup_attribute ("dllexport", DECL_ATTRIBUTES (old))) + { + DECL_DLLIMPORT_P (new) = 0; + warning (OPT_Wattributes, "%q+D already declared with dllexport attribute: " + "dllimport ignored", new); + } + else if (DECL_DLLIMPORT_P (old) && !DECL_DLLIMPORT_P (new)) + { + /* Warn about overriding a symbol that has already been used. eg: + extern int __attribute__ ((dllimport)) foo; + int* bar () {return &foo;} + int foo; + */ + if (TREE_USED (old)) + { + warning (0, "%q+D redeclared without dllimport attribute " + "after being referenced with dll linkage", new); + /* If we have used a variable's address with dllimport linkage, + keep the old DECL_DLLIMPORT_P flag: the ADDR_EXPR using the + decl may already have had TREE_INVARIANT and TREE_CONSTANT + computed. + We still remove the attribute so that assembler code refers + to '&foo rather than '_imp__foo'. */ + if (TREE_CODE (old) == VAR_DECL && TREE_ADDRESSABLE (old)) + DECL_DLLIMPORT_P (new) = 1; + } + + /* Let an inline definition silently override the external reference, + but otherwise warn about attribute inconsistency. */ + else if (TREE_CODE (new) == VAR_DECL + || !DECL_DECLARED_INLINE_P (new)) + warning (OPT_Wattributes, "%q+D redeclared without dllimport attribute: " + "previous dllimport ignored", new); + } else delete_dllimport_p = 0; - a = merge_attributes (old, new); + a = merge_attributes (DECL_ATTRIBUTES (old), DECL_ATTRIBUTES (new)); - if (delete_dllimport_p) + if (delete_dllimport_p) { tree prev, t; - + const size_t attr_len = strlen ("dllimport"); + /* Scan the list for dllimport and delete it. */ for (prev = NULL_TREE, t = a; t; prev = t, t = TREE_CHAIN (t)) { - if (is_attribute_p ("dllimport", TREE_PURPOSE (t))) + if (is_attribute_with_length_p ("dllimport", attr_len, + TREE_PURPOSE (t))) { if (prev == NULL_TREE) a = TREE_CHAIN (a); @@ -3549,18 +3584,26 @@ handle_dll_attribute (tree * pnode, tree name, tree args, int flags, any damage. */ if (is_attribute_p ("dllimport", name)) { + /* Honor any target-specific overides. */ + if (!targetm.valid_dllimport_attribute_p (node)) + *no_add_attrs = true; + + else if (TREE_CODE (node) == FUNCTION_DECL + && DECL_DECLARED_INLINE_P (node)) + { + warning (OPT_Wattributes, "inline function %q+D declared as " + " dllimport: attribute ignored", node); + *no_add_attrs = true; + } /* Like MS, treat definition of dllimported variables and - non-inlined functions on declaration as syntax errors. We - allow the attribute for function definitions if declared - inline. */ - if (TREE_CODE (node) == FUNCTION_DECL && DECL_INITIAL (node) - && !DECL_DECLARED_INLINE_P (node)) + non-inlined functions on declaration as syntax errors. */ + else if (TREE_CODE (node) == FUNCTION_DECL && DECL_INITIAL (node)) { error ("function %q+D definition is marked dllimport", node); *no_add_attrs = true; } - else if (TREE_CODE (node) == VAR_DECL) + else if (TREE_CODE (node) == VAR_DECL) { if (DECL_INITIAL (node)) { @@ -3577,6 +3620,9 @@ handle_dll_attribute (tree * pnode, tree name, tree args, int flags, if (current_function_decl != NULL_TREE && !TREE_STATIC (node)) TREE_PUBLIC (node) = 1; } + + if (*no_add_attrs == false) + DECL_DLLIMPORT_P (node) = 1; } /* Report error if symbol is not accessible at global scope. */ diff --git a/gcc/tree.h b/gcc/tree.h index 08f33fe0d95..144dbd87061 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -2421,9 +2421,8 @@ struct tree_parm_decl GTY(()) #define DECL_GIMPLE_FORMAL_TEMP_P(DECL) \ DECL_WITH_VIS_CHECK (DECL)->decl_with_vis.gimple_formal_temp -/* Used to indicate that the pointer to this DECL cannot be treated as - an address constant. */ -#define DECL_NON_ADDR_CONST_P(NODE) (DECL_WITH_VIS_CHECK (NODE)->decl_with_vis.non_addr_const_p) +/* Used to indicate that the DECL is a dllimport. */ +#define DECL_DLLIMPORT_P(NODE) (DECL_WITH_VIS_CHECK (NODE)->decl_with_vis.dllimport_flag) /* DECL_BASED_ON_RESTRICT_P records whether a VAR_DECL is a temporary based on a variable with a restrict qualified type. If it is, @@ -2514,7 +2513,7 @@ struct tree_decl_with_vis GTY(()) unsigned common_flag:1; unsigned in_text_section : 1; unsigned gimple_formal_temp : 1; - unsigned non_addr_const_p : 1; + unsigned dllimport_flag : 1; unsigned based_on_restrict_p : 1; /* Used by C++. Might become a generic decl flag. */ unsigned shadowed_for_var_p : 1; diff --git a/gcc/varasm.c b/gcc/varasm.c index 286abb3eb93..1aee9839e2d 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -3643,7 +3643,7 @@ initializer_constant_valid_p (tree value, tree endtype) if (value && TREE_CODE (value) == FUNCTION_DECL && ((decl_function_context (value) && !DECL_NO_STATIC_CHAIN (value)) - || DECL_NON_ADDR_CONST_P (value))) + || DECL_DLLIMPORT_P (value))) return NULL_TREE; return value;