People keep submitting bug reports about the compiler crashing when they define std::initializer_list to something broken, so let's diagnose it. I'm not sure where these testcases are coming from, maybe creduce?

Tested x86_64-pc-linux-gnu, applying to trunk.
commit 853b9ecb5c8025c733c756bd9fb20bb64120c649
Author: Jason Merrill <ja...@redhat.com>
Date:   Tue Jul 15 12:09:08 2014 -0400

    	PR c++/60848
    	PR c++/61723
    	* call.c (is_std_init_list): Don't check CLASSTYPE_TEMPLATE_INFO.
    	* class.c (finish_struct): Reject invalid definition of
    	std::initializer_list.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index b16c6e4..cdfe948 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -9699,7 +9699,6 @@ is_std_init_list (tree type)
   type = TYPE_MAIN_VARIANT (type);
   return (CLASS_TYPE_P (type)
 	  && CP_TYPE_CONTEXT (type) == std_node
-	  && CLASSTYPE_TEMPLATE_INFO (type)
 	  && strcmp (TYPE_NAME_STRING (type), "initializer_list") == 0);
 }
 
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index dbd8d3d..e4523c7 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -6695,6 +6695,28 @@ finish_struct (tree t, tree attributes)
   else
     finish_struct_1 (t);
 
+  if (is_std_init_list (t))
+    {
+      /* People keep complaining that the compiler crashes on an invalid
+	 definition of initializer_list, so I guess we should explicitly
+	 reject it.  What the compiler internals care about is that it's a
+	 template and has a pointer field followed by an integer field.  */
+      bool ok = false;
+      if (processing_template_decl)
+	{
+	  tree f = next_initializable_field (TYPE_FIELDS (t));
+	  if (f && TREE_CODE (TREE_TYPE (f)) == POINTER_TYPE)
+	    {
+	      f = next_initializable_field (DECL_CHAIN (f));
+	      if (f && TREE_CODE (TREE_TYPE (f)) == INTEGER_TYPE)
+		ok = true;
+	    }
+	}
+      if (!ok)
+	fatal_error ("definition of std::initializer_list does not match "
+		     "#include <initializer_list>");
+    }
+
   input_location = saved_loc;
 
   TYPE_BEING_DEFINED (t) = 0;
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist85.C b/gcc/testsuite/g++.dg/cpp0x/initlist85.C
index 0eb8e26..fa4fb61 100644
--- a/gcc/testsuite/g++.dg/cpp0x/initlist85.C
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist85.C
@@ -3,12 +3,14 @@
 
 namespace std
 {
-  struct initializer_list {};
+  struct initializer_list {};	// { dg-message "initializer_list" }
 }
 
 void foo(std::initializer_list &);
 
 void f()
 {
-  foo({1, 2});			// { dg-error "" }
+  foo({1, 2});
 }
+
+// { dg-prune-output "compilation terminated" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist87.C b/gcc/testsuite/g++.dg/cpp0x/initlist87.C
new file mode 100644
index 0000000..fd7586d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist87.C
@@ -0,0 +1,35 @@
+// PR c++/61723
+// { dg-do compile { target c++11 } }
+
+namespace std {
+  template < class > struct initializer_list // { dg-message "initializer_list" }
+  {
+#if BUG1
+    int _M_len;
+#endif
+    const int *begin ();
+    const int *end ();
+  };
+}
+
+struct J
+{
+    J (const int &);
+    template < typename InputIterator > J (InputIterator, InputIterator);
+    J (std::initializer_list < int >p1):J (p1.begin (), p1.end ()) { }
+};
+
+struct L
+{
+    L ():dim (0) { }
+    J dim;
+};
+
+void
+fn1 ()
+{
+    L spec;
+    spec.dim = { };
+}
+
+// { dg-prune-output "compilation terminated" }

Reply via email to