PR c++/89083, c++/80864 - ICE with list initialization in template.
authorMarek Polacek <polacek@redhat.com>
Thu, 31 Jan 2019 20:21:11 +0000 (20:21 +0000)
committerMarek Polacek <mpolacek@gcc.gnu.org>
Thu, 31 Jan 2019 20:21:11 +0000 (20:21 +0000)
* constexpr.c (adjust_temp_type): Use copy_node and change the type
instead of using build_constructor.
* decl.c (reshape_init_r): Don't reshape a digested initializer.
Return the initializer for COMPOUND_LITERAL_P.

* g++.dg/cpp0x/initlist107.C: New test.
* g++.dg/cpp0x/initlist108.C: New test.
* g++.dg/cpp0x/initlist109.C: New test.
* g++.dg/cpp0x/initlist110.C: New test.
* g++.dg/cpp0x/initlist111.C: New test.
* g++.dg/cpp0x/initlist112.C: New test.
* g++.dg/init/ptrfn4.C: New test.

From-SVN: r268428

gcc/cp/ChangeLog
gcc/cp/constexpr.c
gcc/cp/decl.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/initlist107.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/initlist108.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/initlist109.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/initlist110.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/initlist111.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/initlist112.C [new file with mode: 0644]
gcc/testsuite/g++.dg/init/ptrfn4.C [new file with mode: 0644]

index a115317a03cb161c8d6dcbf896310f73108bcbcd..a48b14c2091f4ec05017de864b0dcccfd7fa08b5 100644 (file)
@@ -1,3 +1,11 @@
+2019-01-31  Marek Polacek  <polacek@redhat.com>
+
+       PR c++/89083, c++/80864 - ICE with list initialization in template.
+       * constexpr.c (adjust_temp_type): Use copy_node and change the type
+       instead of using build_constructor.
+       * decl.c (reshape_init_r): Don't reshape a digested initializer.
+       Return the initializer for COMPOUND_LITERAL_P.
+
 2019-01-30  Jason Merrill  <jason@redhat.com>
 
        PR c++/88752 - ICE with lambda and constexpr if.
index 426814167600c67640a765eb26dc51934ae91a52..19eb44fc0c059800461cf483e979aa9a3062cf2b 100644 (file)
@@ -1291,7 +1291,12 @@ adjust_temp_type (tree type, tree temp)
     return temp;
   /* Avoid wrapping an aggregate value in a NOP_EXPR.  */
   if (TREE_CODE (temp) == CONSTRUCTOR)
-    return build_constructor (type, CONSTRUCTOR_ELTS (temp));
+    {
+      /* build_constructor wouldn't retain various CONSTRUCTOR flags.  */
+      tree t = copy_node (temp);
+      TREE_TYPE (t) = type;
+      return t;
+    }
   if (TREE_CODE (temp) == EMPTY_CLASS_EXPR)
     return build0 (EMPTY_CLASS_EXPR, type);
   gcc_assert (scalarish_type_p (type));
index 79eeac177b64ce178fdc07eb6ae3d463431a351c..65ba812deb676383909ffbeadd6e50797a3f4e16 100644 (file)
@@ -6154,20 +6154,29 @@ reshape_init_r (tree type, reshape_iter *d, bool first_initializer_p,
     {
       if (TREE_CODE (stripped_init) == CONSTRUCTOR)
        {
-         if (TREE_TYPE (init) && TYPE_PTRMEMFUNC_P (TREE_TYPE (init)))
-           /* There is no need to reshape pointer-to-member function
-              initializers, as they are always constructed correctly
-              by the front end.  */
-           ;
-         else if (COMPOUND_LITERAL_P (stripped_init))
+         tree init_type = TREE_TYPE (init);
+         if (init_type && TYPE_PTRMEMFUNC_P (init_type))
+           /* There is no need to call reshape_init for pointer-to-member
+              function initializers, as they are always constructed correctly
+              by the front end.  Here we have e.g. {.__pfn=0B, .__delta=0},
+              which is missing outermost braces.  We should warn below, and
+              one of the routines below will wrap it in additional { }.  */;
          /* For a nested compound literal, there is no need to reshape since
-            brace elision is not allowed. Even if we decided to allow it,
-            we should add a call to reshape_init in finish_compound_literal,
-            before calling digest_init, so changing this code would still
-            not be necessary.  */
-           gcc_assert (!BRACE_ENCLOSED_INITIALIZER_P (stripped_init));
+            we called reshape_init in finish_compound_literal, before calling
+            digest_init.  */
+         else if (COMPOUND_LITERAL_P (stripped_init)
+                  /* Similarly, a CONSTRUCTOR of the target's type is a
+                     previously digested initializer.  */
+                  || same_type_ignoring_top_level_qualifiers_p (type,
+                                                                init_type))
+           {
+             ++d->cur;
+             gcc_assert (!BRACE_ENCLOSED_INITIALIZER_P (stripped_init));
+             return init;
+           }
          else
            {
+             /* Something that hasn't been reshaped yet.  */
              ++d->cur;
              gcc_assert (BRACE_ENCLOSED_INITIALIZER_P (stripped_init));
              return reshape_init (type, init, complain);
index 25cf4cdafaa3ca4bfa7744f44ca660e82153c987..ce63dad84d0952800865fbbb13eef31bfcd3cb5c 100644 (file)
@@ -1,3 +1,14 @@
+2019-01-31  Marek Polacek  <polacek@redhat.com>
+
+       PR c++/89083, c++/80864 - ICE with list initialization in template.
+       * g++.dg/cpp0x/initlist107.C: New test.
+       * g++.dg/cpp0x/initlist108.C: New test.
+       * g++.dg/cpp0x/initlist109.C: New test.
+       * g++.dg/cpp0x/initlist110.C: New test.
+       * g++.dg/cpp0x/initlist111.C: New test.
+       * g++.dg/cpp0x/initlist112.C: New test.
+       * g++.dg/init/ptrfn4.C: New test.
+
 2019-01-31  David Malcolm  <dmalcolm@redhat.com>
 
        PR c/89122
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist107.C b/gcc/testsuite/g++.dg/cpp0x/initlist107.C
new file mode 100644 (file)
index 0000000..9acfe7c
--- /dev/null
@@ -0,0 +1,24 @@
+// PR c++/89083
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wmissing-braces" }
+
+struct A { int x[3]; };
+
+template<class T>
+decltype(A{1, 2}, T()) fn1(T t) // { dg-warning "missing braces" }
+{
+  return t;
+}
+
+template<class T>
+decltype(A{{1, 2}}, T()) fn2(T t)
+{
+  return t;
+}
+
+void
+f()
+{
+  fn1(1);
+  fn2(1);
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist108.C b/gcc/testsuite/g++.dg/cpp0x/initlist108.C
new file mode 100644 (file)
index 0000000..e283978
--- /dev/null
@@ -0,0 +1,34 @@
+// PR c++/80864
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wmissing-braces" }
+
+struct S {
+  char c[1];
+};
+
+template <typename T>
+void
+fn ()
+{
+   constexpr S s1 = S{};
+   constexpr S s2 = S{{}};
+   constexpr S s3 = S{{{}}};
+   constexpr S s4 = {};
+   constexpr S s5 = {{}};
+   constexpr S s6 = {{{}}};
+   constexpr S s7{{}};
+   constexpr S s8{S{}};
+   constexpr S s9{S{{}}};
+   constexpr S s10{S{{{}}}};
+   constexpr S s11 = S();
+   constexpr S s12 = S({});
+   constexpr S s13 = S({{}});
+   constexpr S s14 = {{}};
+   constexpr S s15 = {{{}}};
+}
+
+void
+foo ()
+{
+  fn<int>();
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist109.C b/gcc/testsuite/g++.dg/cpp0x/initlist109.C
new file mode 100644 (file)
index 0000000..1351a2d
--- /dev/null
@@ -0,0 +1,15 @@
+// PR c++/80864
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wmissing-braces" }
+
+struct S {};
+struct A { S s[1]; };
+
+template <typename>
+struct R { static constexpr auto h = A{S{}}; }; // { dg-warning "missing braces" }
+
+template <typename>
+struct R2 { static constexpr auto h = A{{S{}}}; };
+
+A foo = R<int>::h;
+A foo2 = R2<int>::h;
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist110.C b/gcc/testsuite/g++.dg/cpp0x/initlist110.C
new file mode 100644 (file)
index 0000000..7bb229c
--- /dev/null
@@ -0,0 +1,32 @@
+// PR c++/89083
+// { dg-do compile { target c++11 } }
+
+struct C { int a[3]; int i; };
+struct B { C c[3]; };
+struct A { B b[3]; };
+
+template<class T, int N>
+decltype(A{N, N}, T()) fn1(T t)
+{
+  return t;
+}
+
+template<class T, int N>
+decltype(A{{{N, N, N}, {N + 1}}}, T()) fn2(T t)
+{
+  return t;
+}
+
+template<class T, int N, int M>
+decltype(A{{N + M}}, T()) fn3(T t)
+{
+  return t;
+}
+
+void
+f()
+{
+  fn1<int, 10>(1);
+  fn2<int, 10>(1);
+  fn3<int, 10, 20>(1);
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist111.C b/gcc/testsuite/g++.dg/cpp0x/initlist111.C
new file mode 100644 (file)
index 0000000..7f96115
--- /dev/null
@@ -0,0 +1,32 @@
+// PR c++/80864
+// { dg-do compile { target c++11 } }
+
+struct S {
+  int c[3];
+};
+
+template <typename T, int N>
+void
+fn ()
+{
+   constexpr S s1 = S{N};
+   constexpr S s2 = S{{N, N}};
+   constexpr S s3 = S{N, N};
+   constexpr S s4 = {N};
+   constexpr S s5 = {{N}};
+   constexpr S s6 = {N, N};
+   constexpr S s7{{N}};
+   constexpr S s8{S{N}};
+   constexpr S s9{S{{N}}};
+   constexpr S s10{S{{N}}};
+   constexpr S s11 = S({N});
+   constexpr S s12 = S({{N}});
+   constexpr S s13 = {{N}};
+   constexpr S s14 = {{N, N, N}};
+}
+
+void
+foo ()
+{
+  fn<int, 10>();
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist112.C b/gcc/testsuite/g++.dg/cpp0x/initlist112.C
new file mode 100644 (file)
index 0000000..cd97098
--- /dev/null
@@ -0,0 +1,14 @@
+// PR c++/80864
+// { dg-do compile { target c++11 } }
+
+struct S {int a[2]; };
+struct A { S s[1]; };
+
+template <typename, int N>
+struct R { static constexpr auto h = A{S{N}}; };
+
+template <typename, int N>
+struct R2 { static constexpr auto h = A{S{{N, N}}}; };
+
+A foo = R<int, 10>::h;
+A foo2 = R2<int, 10>::h;
diff --git a/gcc/testsuite/g++.dg/init/ptrfn4.C b/gcc/testsuite/g++.dg/init/ptrfn4.C
new file mode 100644 (file)
index 0000000..e1635c8
--- /dev/null
@@ -0,0 +1,19 @@
+// { dg-do compile }
+// { dg-options "-Wmissing-braces" }
+
+struct S { };
+typedef void (S::*fptr1) (int);
+
+struct A {
+  fptr1 f;
+};
+
+A a[] =
+{
+ (fptr1) 0,
+}; // { dg-warning "missing braces around initializer" }
+
+A a2[] =
+{
+ { (fptr1) 0 }
+};