This avoids using native_interpret_type when we cannot do it with
the original type of the variable, instead use an integer type
for the initialization and side-step the size limitation of
native_interpret_int.

Bootstrapped on x86_64-unknown-linux-gnu, testing in progress
(note the reported ICE happens on aarch64 only)

Richard.

2021-09-16  Richard Biener  <rguent...@suse.de>

        PR middle-end/102360
        * internal-fn.c (expand_DEFERRED_INIT): Make pattern-init
        of non-memory more robust.

        * g++.dg/pr102360.C: New testcase.
---
 gcc/internal-fn.c               | 24 ++++++---------
 gcc/testsuite/g++.dg/pr102360.C | 54 +++++++++++++++++++++++++++++++++
 2 files changed, 63 insertions(+), 15 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/pr102360.C

diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index b1283690080..842e320c31d 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -3045,23 +3045,17 @@ expand_DEFERRED_INIT (internal_fn, gcall *stmt)
 
       if (init_type == AUTO_INIT_PATTERN)
        {
-         tree alt_type = NULL_TREE;
-         if (!can_native_interpret_type_p (var_type))
-           {
-             alt_type
-               = lang_hooks.types.type_for_mode (TYPE_MODE (var_type),
-                                                 TYPE_UNSIGNED (var_type));
-             gcc_assert (can_native_interpret_type_p (alt_type));
-           }
-
          unsigned char *buf = (unsigned char *) xmalloc (total_bytes);
          memset (buf, INIT_PATTERN_VALUE, total_bytes);
-         init = native_interpret_expr (alt_type ? alt_type : var_type,
-                                       buf, total_bytes);
-         gcc_assert (init);
-
-         if (alt_type)
-           init = build1 (VIEW_CONVERT_EXPR, var_type, init);
+         if (can_native_interpret_type_p (var_type))
+           init = native_interpret_expr (var_type, buf, total_bytes);
+         else
+           {
+             tree itype = build_nonstandard_integer_type (total_bytes * 8, 1);
+             wide_int w = wi::from_buffer (buf, total_bytes);
+             init = build1 (VIEW_CONVERT_EXPR, var_type,
+                            wide_int_to_tree (itype, w));
+           }
        }
 
       expand_assignment (lhs, init, false);
diff --git a/gcc/testsuite/g++.dg/pr102360.C b/gcc/testsuite/g++.dg/pr102360.C
new file mode 100644
index 00000000000..fdf9e08b283
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr102360.C
@@ -0,0 +1,54 @@
+// { dg-do compile }
+// { dg-options "-fno-tree-dse -O1 -ftrivial-auto-var-init=pattern" }
+
+class A;
+template <typename _Tp, int m, int n> class B {
+public:
+  _Tp val[m * n];
+};
+class C {
+public:
+  C(A);
+};
+struct D {
+  D();
+  unsigned long &operator[](int);
+  unsigned long *p;
+};
+class A {
+public:
+  template <typename _Tp, int m, int n> A(const B<_Tp, m, n> &, bool);
+  int rows, cols;
+  unsigned char *data;
+  unsigned char *datastart;
+  unsigned char *dataend;
+  unsigned char *datalimit;
+  D step;
+};
+template <typename _Tp, int m, int n>
+A::A(const B<_Tp, m, n> &p1, bool)
+    : rows(m), cols(n) {
+  step[0] = cols * sizeof(_Tp);
+  datastart = data = (unsigned char *)p1.val;
+  datalimit = dataend = datastart + rows * step[0];
+}
+class F {
+public:
+  static void compute(C);
+  template <typename _Tp, int m, int n, int nm>
+  static void compute(const B<_Tp, m, n> &, B<_Tp, nm, 1> &, B<_Tp, m, nm> &,
+                      B<_Tp, n, nm> &);
+};
+D::D() {}
+unsigned long &D::operator[](int p1) { return p[p1]; }
+template <typename _Tp, int m, int n, int nm>
+void F::compute(const B<_Tp, m, n> &, B<_Tp, nm, 1> &, B<_Tp, m, nm> &,
+                B<_Tp, n, nm> &p4) {
+  A a(p4, false);
+  compute(a);
+}
+void fn1() {
+  B<double, 4, 4> b, c, e;
+  B<double, 4, 1> d;
+  F::compute(b, d, c, e);
+}
-- 
2.31.1

Reply via email to