From dac45b5c091237cb7e8f723e75b3897a8f763432 Mon Sep 17 00:00:00 2001
From: Mark Mitchell <mark@codesourcery.com>
Date: Fri, 11 Oct 2002 19:55:21 +0000
Subject: [PATCH] re PR c++/5661 (Gcc 3.0.3 Seg faults compiling bad code)

	PR c++/5661
	* cp-tree.h (variably_modified_type_p): New function.
	(grokdeclarator) Tighten check for variably modified types as
	fields.
	* pt.c (convert_template_argument): Do not allow variably modified
	types as template arguments.
	* tree.c (variably_modified_type_p): New function.

	PR c++/5661
	* g++.dg/ext/vlm1.C: New test.
	* g++.dg/ext/vlm2.C: Likewise.

From-SVN: r58060
---
 gcc/cp/ChangeLog                |  8 ++++
 gcc/cp/cp-tree.h                |  1 +
 gcc/cp/decl.c                   | 21 ++++-------
 gcc/cp/pt.c                     | 10 +++++
 gcc/cp/tree.c                   | 66 +++++++++++++++++++++++++++++++++
 gcc/testsuite/ChangeLog         |  4 ++
 gcc/testsuite/g++.dg/ext/vlm1.C | 13 +++++++
 gcc/testsuite/g++.dg/ext/vlm2.C | 13 +++++++
 8 files changed, 123 insertions(+), 13 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/vlm1.C
 create mode 100644 gcc/testsuite/g++.dg/ext/vlm2.C

diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 3246ea23705e..5704c9006639 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -11,6 +11,14 @@
 
 2002-10-11  Mark Mitchell  <mark@codesourcery.com>
 
+	PR c++/5661
+	* cp-tree.h (variably_modified_type_p): New function.
+	(grokdeclarator) Tighten check for variably modified types as
+	fields.
+	* pt.c (convert_template_argument): Do not allow variably modified
+	types as template arguments.
+	* tree.c (variably_modified_type_p): New function.	
+
 	* NEWS: Document removal of "new X = ..." extension.
 	* class.c (initialize_array): Set TREE_HAS_CONSTRUCTOR on
 	brace-enclosed initializers.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 97b7177d14b9..d3d064a0dadc 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4179,6 +4179,7 @@ extern tree cxx_unsave_expr_now			PARAMS ((tree));
 extern tree cxx_maybe_build_cleanup		PARAMS ((tree));
 extern void init_tree			        PARAMS ((void));
 extern int pod_type_p				PARAMS ((tree));
+extern bool variably_modified_type_p            (tree);
 extern int zero_init_p				PARAMS ((tree));
 extern tree canonical_type_variant              PARAMS ((tree));
 extern void unshare_base_binfos			PARAMS ((tree));
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index f8202b46e46c..4401954adcba 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -10928,19 +10928,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
 
 	    type = create_array_type_for_decl (dname, type, size);
 
-	    /* VLAs never work as fields.  */
-	    if (decl_context == FIELD && !processing_template_decl
-		&& TREE_CODE (type) == ARRAY_TYPE
-		&& TYPE_DOMAIN (type) != NULL_TREE
-		&& !TREE_CONSTANT (TYPE_MAX_VALUE (TYPE_DOMAIN (type))))
-	      {
-		error ("size of member `%D' is not constant", dname);
-		/* Proceed with arbitrary constant size, so that offset
-		   computations don't get confused.  */
-		type = create_array_type_for_decl (dname, TREE_TYPE (type),
-						   integer_one_node);
-	      }
-
 	    ctype = NULL_TREE;
 	  }
 	  break;
@@ -11420,6 +11407,14 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
       type = error_mark_node;
     }
 
+  if (decl_context == FIELD 
+      && !processing_template_decl 
+      && variably_modified_type_p (type))
+    {
+      error ("data member may not have variably modified type `%T'", type);
+      type = error_mark_node;
+    }
+
   if (explicitp == 1 || (explicitp && friendp))
     {
       /* [dcl.fct.spec] The explicit specifier shall only be used in
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 46d91abd301e..ceff84f0a065 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -3467,6 +3467,16 @@ convert_template_argument (parm, arg, args, complain, i, in_decl)
 		       val, t);
 		  return error_mark_node;
 		}
+
+	      /* In order to avoid all sorts of complications, we do
+		 not allow variably-modified types as template
+		 arguments.  */
+	      if (variably_modified_type_p (val))
+		{
+		  error ("template-argument `%T' is a variably modified type",
+			 val);
+		  return error_mark_node;
+		}
 	    }
 	}
     }
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 4b1142b11545..ddc1ce1001ae 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -1958,6 +1958,72 @@ pod_type_p (t)
   return 1;
 }
 
+/* Returns true if T is a variably modified type, in the sense of
+   C99.
+
+   In C99, a struct type is never variably modified because a VLA may
+   not appear as a structure member.  However, in GNU C code like:
+    
+     struct S { int i[f()]; };
+
+   is valid.  Even though GNU C++ does not allow that, this function
+   may sometimes be used in the C front end, so it treats any type
+   with variable size in the same way that C99 treats VLAs.
+
+   In particular, a variably modified type is one that involves a type
+   with variable size.  */
+
+bool
+variably_modified_type_p (tree type)
+{
+  /* If TYPE itself has variable size, it is variably modified.  
+
+     We do not yet have a representation of the C99 '[*]' syntax.
+     When a representation is chosen, this function should be modified
+     to test for that case as well.  */
+  if (TYPE_SIZE (type) 
+      && TYPE_SIZE (type) != error_mark_node
+      && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
+    return true;
+
+  /* If TYPE is a pointer or reference, it is variably modified if and
+     only if the type pointed to is variably modified.  */
+  if (TYPE_PTR_P (type)
+      || TREE_CODE (type) == REFERENCE_TYPE)
+    return variably_modified_type_p (TREE_TYPE (type));
+  
+  /* If TYPE is an array, it is variably modified if the array
+     elements are.  (Note that the VLA case has alredy been checked
+     above).  */
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    return variably_modified_type_p (TREE_TYPE (type));
+
+  /* If TYPE is a pointer-to-member, it is variably modified if either
+     the class or the member are variably modified.  */
+  if (TYPE_PTRMEM_P (type) || TYPE_PTRMEMFUNC_P (type))
+    return (variably_modified_type_p (TYPE_PTRMEM_CLASS_TYPE (type))
+	    || variably_modified_type_p (TYPE_PTRMEM_POINTED_TO_TYPE (type)));
+
+  /* If TYPE Is a function type, it is variably modified if any of the
+     parameters or the return type are variably modified.  */
+  if (TREE_CODE (type) == FUNCTION_TYPE
+      || TREE_CODE (type) == METHOD_TYPE)
+    {
+      tree parm;
+
+      if (variably_modified_type_p (TREE_TYPE (type)))
+	return true;
+      for (parm = TYPE_ARG_TYPES (type); 
+	   parm && parm != void_list_node; 
+	   parm = TREE_CHAIN (parm))
+	if (variably_modified_type_p (TREE_VALUE (parm)))
+	  return true;
+    }
+
+  /* All other types are not variably modified.  */
+  return false;
+}
+
 /* Returns 1 iff zero initialization of type T means actually storing
    zeros in it.  */
 
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 882e0227acc6..f04daad57d38 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,9 @@
 2002-10-11  Mark Mitchell  <mark@codesourcery.com>
 
+	PR c++/5661
+	* g++.dg/ext/vlm1.C: New test.
+	* g++.dg/ext/vlm2.C: Likewise.
+	
 	* g++.dg/init/array1.C: Remove invalid braces.
 	* g++.dg/init/brace1.C: New test.
 	* g++.dg/init/copy2.C: Likewise.
diff --git a/gcc/testsuite/g++.dg/ext/vlm1.C b/gcc/testsuite/g++.dg/ext/vlm1.C
new file mode 100644
index 000000000000..61628e6bba48
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/vlm1.C
@@ -0,0 +1,13 @@
+// { dg-options "" }
+
+template <class T> struct A {};
+ 
+struct B {
+  static const int s;
+  A<int[s]> a; // { dg-error "variably modified|no type" }
+};
+ 
+const int B::s=16;
+ 
+B b;
+ 
diff --git a/gcc/testsuite/g++.dg/ext/vlm2.C b/gcc/testsuite/g++.dg/ext/vlm2.C
new file mode 100644
index 000000000000..3a0b335262c1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/vlm2.C
@@ -0,0 +1,13 @@
+// { dg-options "" }
+
+int n;
+
+struct Y
+{
+  void f () {
+    typedef int X[n];
+    struct Z {
+      X x; // { dg-error "variably modified" }
+    };
+  }
+};
-- 
GitLab