diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 3246ea23705..5704c900663 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -11,6 +11,14 @@ 2002-10-11 Mark Mitchell + 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 97b7177d14b..d3d064a0dad 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 f8202b46e46..4401954adcb 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 46d91abd301..ceff84f0a06 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 4b1142b1154..ddc1ce1001a 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 882e0227acc..f04daad57d3 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,9 @@ 2002-10-11 Mark Mitchell + 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 00000000000..61628e6bba4 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/vlm1.C @@ -0,0 +1,13 @@ +// { dg-options "" } + +template struct A {}; + +struct B { + static const int s; + A 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 00000000000..3a0b335262c --- /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" } + }; + } +};