aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Mitchell <mark@codesourcery.com>2002-10-11 19:55:21 +0000
committerMark Mitchell <mmitchel@gcc.gnu.org>2002-10-11 19:55:21 +0000
commitdac45b5c091237cb7e8f723e75b3897a8f763432 (patch)
tree4a570b2a83e5295f39745305c4a521b00d6df0f7
parent46dd38849ba39f228f467edab38cfd60e6809b6e (diff)
downloadgcc-dac45b5c091237cb7e8f723e75b3897a8f763432.zip
gcc-dac45b5c091237cb7e8f723e75b3897a8f763432.tar.gz
gcc-dac45b5c091237cb7e8f723e75b3897a8f763432.tar.bz2
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
-rw-r--r--gcc/cp/ChangeLog8
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/decl.c21
-rw-r--r--gcc/cp/pt.c10
-rw-r--r--gcc/cp/tree.c66
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/g++.dg/ext/vlm1.C13
-rw-r--r--gcc/testsuite/g++.dg/ext/vlm2.C13
8 files changed, 123 insertions, 13 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 3246ea2..5704c90 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 97b7177..d3d064a 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 f8202b4..4401954 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 46d91ab..ceff84f 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 4b1142b..ddc1ce1 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 882e022..f04daad 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 0000000..61628e6
--- /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 0000000..3a0b335
--- /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" }
+ };
+ }
+};