diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 26916e81b38..af60798b7c6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2004-08-31 Mark Mitchell + + * hooks.c (hook_bool_void_true): New function. + * hooks.h (hook_bool_void_true): Declare. + * target-def.h (TARGET_CXX): Add + TARGET_CXX_KEY_METHOD_MAY_BE_INLINE. + * target.h (struct cxx): Add key_method_may_be_inline. + * config/arm/arm.c (arm_cxx_key_method_may_be_inline): New + function. + (TARGET_CXX_KEY_METHOD_MAY_BE_INLINE): New macro. + * config/arm/bpabi.h: Use __THUMB_INTERWORK__ instead of + __THUMB_INTERWORK. + 2004-08-31 Denis Chertykov PR target/15417 diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index b942b8202d4..0a0fdfd4ff5 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2004-08-31 Mark Mitchell + + * class.c (key_method): Rename to ... + (determine_key_method): ... this. + (finish_struct_1): Adjust accordingly. + * cp-tree.h (key_method): Declare. + * decl2.c (maybe_emit_vtables): Determine the key method here if + it has not already been done. + 2004-08-31 Ziemowit Laski * Make-lang.in (CXX_AND_OBJCXX_OBJS): Add cp/cp-objcp-common.o. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 21bdfdd2f6f..84c75878888 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -4886,11 +4886,11 @@ layout_class_type (tree t, tree *virtuals_p) splay_tree_delete (empty_base_offsets); } -/* Returns the virtual function with which the vtable for TYPE is - emitted, or NULL_TREE if that heuristic is not applicable to TYPE. */ +/* Determine the "key method" for the class type indicated by TYPE, + and set CLASSTYPE_KEY_METHOD accordingly. */ -static tree -key_method (tree type) +void +determine_key_method (tree type) { tree method; @@ -4898,16 +4898,23 @@ key_method (tree type) || processing_template_decl || CLASSTYPE_TEMPLATE_INSTANTIATION (type) || CLASSTYPE_INTERFACE_KNOWN (type)) - return NULL_TREE; + return; + /* The key method is the first non-pure virtual function that is not + inline at the point of class definition. On some targets the + key function may not be inline; those targets should not call + this function until the end of the translation unit. */ for (method = TYPE_METHODS (type); method != NULL_TREE; method = TREE_CHAIN (method)) if (DECL_VINDEX (method) != NULL_TREE && ! DECL_DECLARED_INLINE_P (method) && ! DECL_PURE_VIRTUAL_P (method)) - return method; + { + CLASSTYPE_KEY_METHOD (type) = method; + break; + } - return NULL_TREE; + return; } /* Perform processing required when the definition of T (a class type) @@ -4950,7 +4957,16 @@ finish_struct_1 (tree t) /* Find the key method. */ if (TYPE_CONTAINS_VPTR_P (t)) { - CLASSTYPE_KEY_METHOD (t) = key_method (t); + /* The Itanium C++ ABI permits the key method to be chosen when + the class is defined -- even though the key method so + selected may later turn out to be an inline function. On + some systems (such as ARM Symbian OS) the key method cannot + be determined until the end of the translation unit. On such + systems, we leave CLASSTYPE_KEY_METHOD set to NULL, which + will cause the class to be added to KEYED_CLASSES. Then, in + finish_file we will determine the key method. */ + if (targetm.cxx.key_method_may_be_inline ()) + determine_key_method (t); /* If a polymorphic class has no key method, we may emit the vtable in every translation unit where the class definition appears. */ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 8267f725139..a6db5532023 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -3673,6 +3673,7 @@ extern void debug_class (tree); extern void debug_thunks (tree); extern tree cp_fold_obj_type_ref (tree, tree); extern void set_linkage_according_to_type (tree, tree); +extern void determine_key_method (tree); /* in cvt.c */ extern tree convert_to_reference (tree, tree, int, int, tree); diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 33a9ef52243..d02180a44af 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1559,6 +1559,12 @@ maybe_emit_vtables (tree ctype) if (TREE_TYPE (primary_vtbl) == void_type_node) return false; + /* On some targets, we cannot determine the key method until the end + of the translation unit -- which is when this function is + called. */ + if (!targetm.cxx.key_method_may_be_inline ()) + determine_key_method (ctype); + /* See if any of the vtables are needed. */ for (vtbl = CLASSTYPE_VTABLES (ctype); vtbl; vtbl = TREE_CHAIN (vtbl)) { diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 2a873985703..d1e59cf424a 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -8528,6 +8528,16 @@ the address of the object created/destroyed. The default is to return @code{false}. @end deftypefn +@deftypefn {Target Hook} bool TARGET_CXX_KEY_METHOD_MAY_BE_INLINE (void) +This hook returns true if the key method for a class (i.e., the method +which, if defined in the current translation unit, causes the virtual +table to be emitted) may be an inline function. Under the standard +Itanium C++ ABI the key method may be an inline function so long as +the function is not declared inline in the class definition. Under +some variants of the ABI, an inline function can never be the key +method. The default is to return @code{true}. +@end deftypefn + @node Misc @section Miscellaneous Parameters @cindex parameters, miscellaneous diff --git a/gcc/hooks.c b/gcc/hooks.c index 077f9bf8e0e..6c17a5f4fc7 100644 --- a/gcc/hooks.c +++ b/gcc/hooks.c @@ -41,7 +41,14 @@ hook_bool_void_false (void) return false; } -/* The same, but formally returning NO_REGS. */ +/* Generic hook that takes no arguments and returns true. */ +bool +hook_bool_void_true (void) +{ + return true; +} + +/* Generic hook that takes no arguments and returns NO_REGS. */ int hook_int_void_no_regs (void) { diff --git a/gcc/hooks.h b/gcc/hooks.h index a611ba198de..8eef06f3bca 100644 --- a/gcc/hooks.h +++ b/gcc/hooks.h @@ -25,6 +25,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "machmode.h" extern bool hook_bool_void_false (void); +extern bool hook_bool_void_true (void); extern bool hook_bool_bool_false (bool); extern bool hook_bool_mode_false (enum machine_mode); extern bool hook_bool_tree_false (tree); diff --git a/gcc/target-def.h b/gcc/target-def.h index 156ebef7c7b..e49d05584ed 100644 --- a/gcc/target-def.h +++ b/gcc/target-def.h @@ -437,6 +437,10 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define TARGET_CXX_CDTOR_RETURNS_THIS hook_bool_void_false #endif +#ifndef TARGET_CXX_KEY_METHOD_MAY_BE_INLINE +#define TARGET_CXX_KEY_METHOD_MAY_BE_INLINE hook_bool_void_true +#endif + #define TARGET_CXX \ { \ TARGET_CXX_GUARD_TYPE, \ @@ -444,7 +448,8 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. TARGET_CXX_GET_COOKIE_SIZE, \ TARGET_CXX_COOKIE_HAS_SIZE, \ TARGET_CXX_IMPORT_EXPORT_CLASS, \ - TARGET_CXX_CDTOR_RETURNS_THIS \ + TARGET_CXX_CDTOR_RETURNS_THIS, \ + TARGET_CXX_KEY_METHOD_MAY_BE_INLINE \ } /* The whole shebang. */ diff --git a/gcc/target.h b/gcc/target.h index 27e4086129e..57b38cf25f4 100644 --- a/gcc/target.h +++ b/gcc/target.h @@ -516,6 +516,11 @@ struct gcc_target int (*import_export_class) (tree, int); /* Returns true if constructors and destructors return "this". */ bool (*cdtor_returns_this) (void); + /* Returns true if the key method for a class can be an inline + function, so long as it is not declared inline in the class + itself. Returning true is the behavior required by the Itanium + C++ ABI. */ + bool (*key_method_may_be_inline) (void); } cxx; /* Leave the boolean fields at the end. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index e7a17d30e43..5e8be36c636 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2004-08-31 Mark Mitchell + + * g++.dg/abi/key1.C: New test. + 2004-08-31 Richard Henderson * g++.dg/other/offsetof1.C: Include cstddef, use non-builtin diff --git a/gcc/testsuite/g++.dg/abi/key1.C b/gcc/testsuite/g++.dg/abi/key1.C new file mode 100644 index 00000000000..6c038092641 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/key1.C @@ -0,0 +1,26 @@ +// On ARM EABI platforms, key methods may never be inline. +// { dg-do compile { target arm*-*-eabi* arm*-*-symbianelf* } } +// { dg-final { scan-assembler-not _ZTV1S } } +// { dg-final { scan-assembler-not _ZTV1T } } +// { dg-final { scan-assembler _ZTV1U } } + +struct S { + virtual void f(); +}; + +inline void S::f() {} + +struct T { + virtual void g(); + virtual void h(); +}; + +inline void T::g() {} + +struct U { + virtual void i(); + virtual void j(); +}; + +inline void U::i() {} +void U::j () {}