From 46c739d40c6c1028295931c53cf414d581519072 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 7 Apr 2022 09:14:07 +0200 Subject: [PATCH] c++: Handle __builtin_clear_padding on non-trivially-copyable types [PR102586] On Fri, Feb 11, 2022 at 07:55:50PM +0100, Jakub Jelinek via Gcc-patches wrote: > Something like the https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102586#c16 > will still be needed with adjusted testcase from > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102586#c15 such that > __builtin_clear_padding is called directly on var addresses rather than > in separate functions. Here is an updated version of the https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102586#c15 patch which uses FIELD_DECL in the langhook instead of its TREE_TYPE, and the testcases have been adjusted for the builtin accepting pointers to non-trivially-copyable types only if it is address of a declaration. 2022-04-07 Jakub Jelinek PR tree-optimization/102586 gcc/ * langhooks.h (struct lang_hooks_for_types): Add classtype_as_base langhook. * langhooks-def.h (LANG_HOOKS_CLASSTYPE_AS_BASE): Define. (LANG_HOOKS_FOR_TYPES_INITIALIZER): Add it. * gimple-fold.cc (clear_padding_type): Use ftype instead of TREE_TYPE (field) some more. For artificial FIELD_DECLs without name try the lang_hooks.types.classtype_as_base langhook and if it returns non-NULL, use that instead of ftype for recursive call. gcc/cp/ * cp-objcp-common.h (cp_classtype_as_base): Declare. (LANG_HOOKS_CLASSTYPE_AS_BASE): Redefine. * cp-objcp-common.cc (cp_classtype_as_base): New function. gcc/testsuite/ * g++.dg/torture/builtin-clear-padding-5.C: New test. * g++.dg/cpp2a/builtin-clear-padding1.C (bar): Uncomment one call that is now accepted. --- gcc/cp/cp-objcp-common.cc | 16 ++++++++ gcc/cp/cp-objcp-common.h | 3 ++ gcc/gimple-fold.cc | 7 ++-- gcc/langhooks-def.h | 4 +- gcc/langhooks.h | 5 +++ .../g++.dg/cpp2a/builtin-clear-padding1.C | 2 +- .../g++.dg/torture/builtin-clear-padding-5.C | 44 ++++++++++++++++++++++ 7 files changed, 76 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/g++.dg/torture/builtin-clear-padding-5.C diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc index 8f74802..0b70d55 100644 --- a/gcc/cp/cp-objcp-common.cc +++ b/gcc/cp/cp-objcp-common.cc @@ -280,6 +280,22 @@ cp_unit_size_without_reusable_padding (tree type) return TYPE_SIZE_UNIT (type); } +/* Returns type corresponding to FIELD's type when FIELD is a C++ base class + i.e., type without virtual base classes or tail padding. Returns + NULL_TREE otherwise. */ + +tree +cp_classtype_as_base (const_tree field) +{ + if (DECL_FIELD_IS_BASE (field)) + { + tree type = TREE_TYPE (field); + if (TYPE_LANG_SPECIFIC (type)) + return CLASSTYPE_AS_BASE (type); + } + return NULL_TREE; +} + /* Stubs to keep c-opts.cc happy. */ void push_file_scope (void) diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h index 4c13731..3c04e5c 100644 --- a/gcc/cp/cp-objcp-common.h +++ b/gcc/cp/cp-objcp-common.h @@ -31,6 +31,7 @@ extern int cp_decl_dwarf_attribute (const_tree, int); extern int cp_type_dwarf_attribute (const_tree, int); extern void cp_common_init_ts (void); extern tree cp_unit_size_without_reusable_padding (tree); +extern tree cp_classtype_as_base (const_tree); extern tree cp_get_global_decls (); extern tree cp_pushdecl (tree); extern void cp_register_dumps (gcc::dump_manager *); @@ -167,6 +168,8 @@ extern tree cxx_simulate_record_decl (location_t, const char *, #define LANG_HOOKS_TYPE_DWARF_ATTRIBUTE cp_type_dwarf_attribute #undef LANG_HOOKS_UNIT_SIZE_WITHOUT_REUSABLE_PADDING #define LANG_HOOKS_UNIT_SIZE_WITHOUT_REUSABLE_PADDING cp_unit_size_without_reusable_padding +#undef LANG_HOOKS_CLASSTYPE_AS_BASE +#define LANG_HOOKS_CLASSTYPE_AS_BASE cp_classtype_as_base #undef LANG_HOOKS_OMP_PREDETERMINED_SHARING #define LANG_HOOKS_OMP_PREDETERMINED_SHARING cxx_omp_predetermined_sharing diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc index 97880a5..ac22adf 100644 --- a/gcc/gimple-fold.cc +++ b/gcc/gimple-fold.cc @@ -4747,7 +4747,7 @@ clear_padding_type (clear_padding_struct *buf, tree type, "have well defined padding bits for %qs", field, "__builtin_clear_padding"); } - else if (is_empty_type (TREE_TYPE (field))) + else if (is_empty_type (ftype)) continue; else { @@ -4758,8 +4758,9 @@ clear_padding_type (clear_padding_struct *buf, tree type, gcc_assert (pos >= 0 && fldsz >= 0 && pos >= cur_pos); clear_padding_add_padding (buf, pos - cur_pos); cur_pos = pos; - clear_padding_type (buf, TREE_TYPE (field), - fldsz, for_auto_init); + if (tree asbase = lang_hooks.types.classtype_as_base (field)) + ftype = asbase; + clear_padding_type (buf, ftype, fldsz, for_auto_init); cur_pos += fldsz; } } diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h index 49c8f58..e226395 100644 --- a/gcc/langhooks-def.h +++ b/gcc/langhooks-def.h @@ -216,6 +216,7 @@ extern tree lhd_unit_size_without_reusable_padding (tree); #define LANG_HOOKS_GET_FIXED_POINT_TYPE_INFO NULL #define LANG_HOOKS_TYPE_DWARF_ATTRIBUTE lhd_type_dwarf_attribute #define LANG_HOOKS_UNIT_SIZE_WITHOUT_REUSABLE_PADDING lhd_unit_size_without_reusable_padding +#define LANG_HOOKS_CLASSTYPE_AS_BASE hook_tree_const_tree_null #define LANG_HOOKS_FOR_TYPES_INITIALIZER { \ LANG_HOOKS_MAKE_TYPE, \ @@ -243,7 +244,8 @@ extern tree lhd_unit_size_without_reusable_padding (tree); LANG_HOOKS_GET_DEBUG_TYPE, \ LANG_HOOKS_GET_FIXED_POINT_TYPE_INFO, \ LANG_HOOKS_TYPE_DWARF_ATTRIBUTE, \ - LANG_HOOKS_UNIT_SIZE_WITHOUT_REUSABLE_PADDING \ + LANG_HOOKS_UNIT_SIZE_WITHOUT_REUSABLE_PADDING, \ + LANG_HOOKS_CLASSTYPE_AS_BASE \ } /* Declaration hooks. */ diff --git a/gcc/langhooks.h b/gcc/langhooks.h index 0eec1b0..4731f08 100644 --- a/gcc/langhooks.h +++ b/gcc/langhooks.h @@ -188,6 +188,11 @@ struct lang_hooks_for_types /* Returns a tree for the unit size of T excluding tail padding that might be used by objects inheriting from T. */ tree (*unit_size_without_reusable_padding) (tree); + + /* Returns type corresponding to FIELD's type when FIELD is a C++ base class + i.e., type without virtual base classes or tail padding. Returns + NULL_TREE otherwise. */ + tree (*classtype_as_base) (const_tree); }; /* Language hooks related to decls and the symbol table. */ diff --git a/gcc/testsuite/g++.dg/cpp2a/builtin-clear-padding1.C b/gcc/testsuite/g++.dg/cpp2a/builtin-clear-padding1.C index 7b1282e..ed74ebf 100644 --- a/gcc/testsuite/g++.dg/cpp2a/builtin-clear-padding1.C +++ b/gcc/testsuite/g++.dg/cpp2a/builtin-clear-padding1.C @@ -43,7 +43,7 @@ bar () __builtin_clear_padding (&c2); __builtin_clear_padding (&c3); __builtin_clear_padding (&c4); -// __builtin_clear_padding (&c5); + __builtin_clear_padding (&c5); __builtin_clear_padding (&c6); __builtin_clear_padding (&c7); __builtin_clear_padding (&c8); diff --git a/gcc/testsuite/g++.dg/torture/builtin-clear-padding-5.C b/gcc/testsuite/g++.dg/torture/builtin-clear-padding-5.C new file mode 100644 index 0000000..b5f0191 --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/builtin-clear-padding-5.C @@ -0,0 +1,44 @@ +// PR tree-optimization/102586 +// { dg-options "-Wno-inaccessible-base" } + +struct C0 {}; +struct C1 {}; +struct C2 : C1, virtual C0 {}; +struct C3 : virtual C2, C1 { virtual int foo () { return 1; } }; +struct C4 : virtual C3, C1 { virtual int foo () { return 2; } }; +struct C5 : C4 { virtual int foo () { return 3; } }; +struct C6 { char c; }; +struct C7 : virtual C6, virtual C3, C1 { virtual int foo () { return 4; } }; +struct C8 : C7 { virtual int foo () { return 5; } }; + +__attribute__((noipa)) int +bar (C5 *p) +{ + return p->foo (); +} + +__attribute__((noipa)) int +baz (C3 *p) +{ + return p->foo (); +} + +__attribute__((noipa)) int +qux (C8 *p) +{ + return p->foo (); +} + +int +main () +{ + C5 c5; + C8 c8; + c8.c = 42; + __builtin_clear_padding (&c5); + __builtin_clear_padding (&c8); + if (bar (&c5) != 3 || baz (&c5) != 3) + __builtin_abort (); + if (qux (&c8) != 5 || baz (&c8) != 5 || c8.c != 42) + __builtin_abort (); +} -- 2.7.4