fold-const: Don't use build_constructor for non-aggregate types in native_encode_init...
authorJakub Jelinek <jakub@redhat.com>
Fri, 4 Dec 2020 17:00:54 +0000 (18:00 +0100)
committerJakub Jelinek <jakub@redhat.com>
Fri, 4 Dec 2020 17:02:10 +0000 (18:02 +0100)
The following testcase is rejected, because when trying to encode a zeroing
CONSTRUCTOR, the code was using build_constructor to build initializers for
the elements but when recursing the function handles CONSTRUCTOR only for
aggregate types.

The following patch fixes that by using build_zero_cst instead for
non-aggregates.  Another option would be add handling CONSTRUCTOR for
non-aggregates in native_encode_initializer.  Or we can do both, I guess
the middle-end generally doesn't like CONSTRUCTORs for scalar variables, but
am not 100% sure if the FE doesn't produce those sometimes.

2020-12-04  Jakub Jelinek  <jakub@redhat.com>

PR libstdc++/93121
* fold-const.c (native_encode_initializer): Use build_zero_cst
instead of build_constructor.

* g++.dg/cpp2a/bit-cast6.C: New test.

gcc/fold-const.c
gcc/testsuite/g++.dg/cpp2a/bit-cast6.C [new file with mode: 0644]

index e77d74e40b06a68076a53dc2b9840ac0c640d69d..1241b1395d49a6a061e8af508f9ad64cda363373 100644 (file)
@@ -8104,11 +8104,12 @@ native_encode_initializer (tree init, unsigned char *ptr, int len,
                {
                  if (valueinit == -1)
                    {
-                     tree zero = build_constructor (TREE_TYPE (type), NULL);
+                     tree zero = build_zero_cst (TREE_TYPE (type));
                      r = native_encode_initializer (zero, ptr + curpos,
                                                     fieldsize, 0,
                                                     mask + curpos);
-                     ggc_free (zero);
+                     if (TREE_CODE (zero) == CONSTRUCTOR)
+                       ggc_free (zero);
                      if (!r)
                        return 0;
                      valueinit = curpos;
@@ -8255,8 +8256,9 @@ native_encode_initializer (tree init, unsigned char *ptr, int len,
                    {
                      cnt--;
                      field = fld;
-                     val = build_constructor (TREE_TYPE (fld), NULL);
-                     to_free = val;
+                     val = build_zero_cst (TREE_TYPE (fld));
+                     if (TREE_CODE (val) == CONSTRUCTOR)
+                       to_free = val;
                    }
                }
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/bit-cast6.C b/gcc/testsuite/g++.dg/cpp2a/bit-cast6.C
new file mode 100644 (file)
index 0000000..4b70da1
--- /dev/null
@@ -0,0 +1,31 @@
+// PR libstd++/93121
+// { dg-do compile { target c++20 } }
+
+namespace std
+{
+enum class byte : unsigned char {};
+template <typename To, typename From>
+constexpr To
+bit_cast (const From &from)
+{
+  return __builtin_bit_cast (To, from);
+}
+}
+
+struct S { unsigned short s[2]; };
+constexpr std::byte from1[sizeof (S)]{};
+constexpr auto to1 = std::bit_cast<S>(from1);
+constexpr unsigned char from2[sizeof (S)]{};
+constexpr auto to2 = std::bit_cast<S>(from2);
+
+constexpr bool
+cmp (const S &s1, const S &s2)
+{
+  for (int i = 0; i < sizeof (s1.s) / sizeof (s1.s[0]); i++)
+    if (s1.s[i] != s2.s[i])
+      return false;
+  return true;
+}
+
+static_assert (cmp (to1, S{}));
+static_assert (cmp (to2, S{}));