On 10/22/19 11:03 AM, Jakub Jelinek wrote:
Hi!
The following patch is just a partial fix for a regression introduced
in the PR90947 changes, the testcase is fixed for just C++17/20.
type_initializer_zero_p has been added to the generic code, supposedly
because similar initializer_zerop is in generic code too, but that
means it has a hand-written copy of next_initializable_field which can't
do exactly what next_initializable_field does.
The following patch moves it into the C++ FE which is the only user of that
function and uses next_initializable_field in there.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
I'm afraid I'm lost on how to fix the C++11/14 case, the object
being initialized has std::atomic<int> type, which doesn't have any
direct non-static data members, and has std::__atomic_base<int> as base
class that has some field. The only FIELD_DECL in std::atomic<int>
is DECL_ARTIFICIAL field for the base class, so next_initializable_field
or the hand-written variant thereof doesn't find any initializable fields
for 11/14. The initializer is initializer list { {1} } and the function
just returns true if it doesn't find any initializable fields, so in the end
we misoptimize it as { {0} }.
I think type_initializer_zero_p should return false if
CLASSTYPE_NON_AGGREGATE; we can't expect that value-initialization will
have the intended effect in that case.
2019-10-22 Jakub Jelinek <ja...@redhat.com>
PR c++/90947
* tree.h (type_initializer_zero_p): Remove.
* tree.c (type_initializer_zero_p): Remove.
cp/
* cp-tree.h (type_initializer_zero_p): Declare.
* decl.c (reshape_init_array_1): Formatting fix.
* tree.c (type_initializer_zero_p): New function. Moved from
../tree.c, use next_initializable_field, formatting fix.
--- gcc/tree.h.jj 2019-09-20 12:25:13.737920929 +0200
+++ gcc/tree.h 2019-10-22 10:07:26.411826804 +0200
@@ -4690,12 +4690,6 @@ extern tree first_field (const_tree);
extern bool initializer_zerop (const_tree, bool * = NULL);
extern bool initializer_each_zero_or_onep (const_tree);
-/* Analogous to initializer_zerop but also examines the type for
- which the initializer is being used. Unlike initializer_zerop,
- considers empty strings to be zero initializers for arrays and
- non-zero for pointers. */
-extern bool type_initializer_zero_p (tree, tree);
-
extern wide_int vector_cst_int_elt (const_tree, unsigned int);
extern tree vector_cst_elt (const_tree, unsigned int);
--- gcc/tree.c.jj 2019-10-19 09:22:14.830893404 +0200
+++ gcc/tree.c 2019-10-22 10:08:36.501748481 +0200
@@ -11396,73 +11396,6 @@ initializer_each_zero_or_onep (const_tre
}
}
-/* Given an initializer INIT for a TYPE, return true if INIT is zero
- so that it can be replaced by value initialization. This function
- distinguishes betwen empty strings as initializers for arrays and
- for pointers (which make it return false). */
-
-bool
-type_initializer_zero_p (tree type, tree init)
-{
- if (type == error_mark_node || init == error_mark_node)
- return false;
-
- STRIP_NOPS (init);
-
- if (POINTER_TYPE_P (type))
- return TREE_CODE (init) != STRING_CST && initializer_zerop (init);
-
- if (TREE_CODE (init) != CONSTRUCTOR)
- return initializer_zerop (init);
-
- if (TREE_CODE (type) == ARRAY_TYPE)
- {
- tree elt_type = TREE_TYPE (type);
- elt_type = TYPE_MAIN_VARIANT (elt_type);
- if (elt_type == char_type_node)
- return initializer_zerop (init);
-
- tree elt_init;
- unsigned HOST_WIDE_INT i;
- FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (init), i, elt_init)
- if (!type_initializer_zero_p (elt_type, elt_init))
- return false;
- return true;
- }
-
- if (TREE_CODE (type) != RECORD_TYPE)
- return initializer_zerop (init);
-
- tree fld = TYPE_FIELDS (type);
-
- tree fld_init;
- unsigned HOST_WIDE_INT i;
- FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (init), i, fld_init)
- {
- /* Advance to the next member, skipping over everything that
- canot be initialized (including unnamed bit-fields). */
- while (TREE_CODE (fld) != FIELD_DECL
- || DECL_ARTIFICIAL (fld)
- || (DECL_BIT_FIELD (fld) && !DECL_NAME (fld)))
- {
- fld = DECL_CHAIN (fld);
- if (!fld)
- return true;
- continue;
- }
-
- tree fldtype = TREE_TYPE (fld);
- if (!type_initializer_zero_p (fldtype, fld_init))
- return false;
-
- fld = DECL_CHAIN (fld);
- if (!fld)
- break;
- }
-
- return true;
-}
-
/* Check if vector VEC consists of all the equal elements and
that the number of elements corresponds to the type of VEC.
The function returns first element of the vector
--- gcc/cp/cp-tree.h.jj 2019-10-22 08:15:53.810775827 +0200
+++ gcc/cp/cp-tree.h 2019-10-22 10:10:57.265582861 +0200
@@ -7379,6 +7379,11 @@ extern tree cxx_copy_lang_qualifiers (c
extern void cxx_print_statistics (void);
extern bool maybe_warn_zero_as_null_pointer_constant (tree, location_t);
+/* Analogous to initializer_zerop but also examines the type for
+ which the initializer is being used. Unlike initializer_zerop,
+ considers empty strings to be zero initializers for arrays and
+ non-zero for pointers. */
+extern bool type_initializer_zero_p (tree, tree);
/* in ptree.c */
extern void cxx_print_xnode (FILE *, tree, int);
--- gcc/cp/decl.c.jj 2019-10-22 08:57:12.913654620 +0200
+++ gcc/cp/decl.c 2019-10-22 10:13:39.038094034 +0200
@@ -5982,9 +5982,8 @@ reshape_init_array_1 (tree elt_type, tre
/* Pointers initialized to strings must be treated as non-zero
even if the string is empty. */
tree init_type = TREE_TYPE (elt_init);
- if ((POINTER_TYPE_P (elt_type) != POINTER_TYPE_P (init_type)))
- last_nonzero = index;
- else if (!type_initializer_zero_p (elt_type, elt_init))
+ if (POINTER_TYPE_P (elt_type) != POINTER_TYPE_P (init_type)
+ || !type_initializer_zero_p (elt_type, elt_init))
last_nonzero = index;
/* This can happen with an invalid initializer (c++/54501). */
--- gcc/cp/tree.c.jj 2019-10-19 09:22:16.594866462 +0200
+++ gcc/cp/tree.c 2019-10-22 10:10:29.151015397 +0200
@@ -5527,6 +5527,65 @@ maybe_warn_zero_as_null_pointer_constant
return false;
}
+/* Given an initializer INIT for a TYPE, return true if INIT is zero
+ so that it can be replaced by value initialization. This function
+ distinguishes betwen empty strings as initializers for arrays and
+ for pointers (which make it return false). */
+
+bool
+type_initializer_zero_p (tree type, tree init)
+{
+ if (type == error_mark_node || init == error_mark_node)
+ return false;
+
+ STRIP_NOPS (init);
+
+ if (POINTER_TYPE_P (type))
+ return TREE_CODE (init) != STRING_CST && initializer_zerop (init);
+
+ if (TREE_CODE (init) != CONSTRUCTOR)
+ return initializer_zerop (init);
+
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ tree elt_type = TREE_TYPE (type);
+ elt_type = TYPE_MAIN_VARIANT (elt_type);
+ if (elt_type == char_type_node)
+ return initializer_zerop (init);
+
+ tree elt_init;
+ unsigned HOST_WIDE_INT i;
+ FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (init), i, elt_init)
+ if (!type_initializer_zero_p (elt_type, elt_init))
> + return false;
+ return true;
+ }
+
+ if (TREE_CODE (type) != RECORD_TYPE)
+ return initializer_zerop (init);
+
+ tree fld = TYPE_FIELDS (type);
+
+ tree fld_init;
+ unsigned HOST_WIDE_INT i;
+ FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (init), i, fld_init)
+ {
+ fld = next_initializable_field (fld);
+ if (!fld)
+ return true;
+
+ tree fldtype = TREE_TYPE (fld);
+ if (!type_initializer_zero_p (fldtype, fld_init))
+ return false;
+
+ fld = DECL_CHAIN (fld);
+ if (!fld)
+ break;
+ }
+
+ return true;
+}
+
#if defined ENABLE_TREE_CHECKING && (GCC_VERSION >= 2007)
/* Complain that some language-specific thing hanging off a tree
node has been accessed improperly. */
Jakub