From 68a3e7e1aa16b596e6e0bb924d003cf79d68f308 Mon Sep 17 00:00:00 2001 From: Zack Weinberg Date: Fri, 25 Oct 2002 22:11:19 +0000 Subject: [PATCH] re PR c++/6994 (ICE in find_function_data) PR middle-end/6994 * c-objc-common.c (inline_forbidden_p): Can not inline functions containing structures or unions containing VLAs. * tree-inline.c (walk_tree): For all class 't' nodes, walk TYPE_SIZE and TYPE_SIZE_UNIT. #undef WALK_SUBTREE_TAIL at end. (copy_tree_r): Copy types if they are variably modified. * hooks.c (hook_tree_bool_false): New. * hooks.h: Prototype it. * langhooks.h (struct lang_hooks_for_tree_inlining): Add var_mod_type_p. * langhooks-def.h: Default for tree_inlining.var_mod_type_p is hook_tree_bool_false. * tree.c (variably_modified_type_p): Moved here from cp/tree.c. Use lang_hooks.tree_inlining.var_mod_type_p for language-specific cases. Due to this, must weaken some 'if and only if' checks to merely 'if'. * tree.h: Prototype variably_modified_type_p. cp: * cp-lang.c (cp_var_mod_type_p): New: C++ hook for variably_modified_type_p. * cp-tree.h: Remove prototype of variably_modified_type_p. * tree.c (variably_modified_type_p): Remove; now implemented in language-independent code. PR c++/7266 * decl.c (grokdeclarator): Check that TREE_OPERAND 0 of a SCOPE_REF is not null before dereferencing it. testsuite: * g++.dg/ext/vla1.C, gcc.dg/vla-2.c, g++.dg/template/typename3.C: New tests. From-SVN: r58542 --- gcc/ChangeLog | 22 ++++++++++++++ gcc/c-objc-common.c | 16 ++++++++++ gcc/cp/ChangeLog | 13 ++++++++ gcc/cp/cp-lang.c | 21 +++++++++++++ gcc/cp/cp-tree.h | 1 - gcc/cp/decl.c | 5 ++-- gcc/cp/tree.c | 66 ----------------------------------------- gcc/hooks.c | 8 +++++ gcc/hooks.h | 1 + gcc/langhooks-def.h | 3 ++ gcc/langhooks.h | 1 + gcc/testsuite/ChangeLog | 7 ++++- gcc/tree-inline.c | 11 +++++-- gcc/tree.c | 59 ++++++++++++++++++++++++++++++++++++ gcc/tree.h | 1 + 15 files changed, 163 insertions(+), 72 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a9f03f10d7b4..c5f7db3a8ce3 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,25 @@ +2002-10-25 Zack Weinberg + + PR middle-end/6994 + * c-objc-common.c (inline_forbidden_p): Can not inline + functions containing structures or unions containing VLAs. + * tree-inline.c (walk_tree): For all class 't' nodes, walk + TYPE_SIZE and TYPE_SIZE_UNIT. #undef WALK_SUBTREE_TAIL at end. + (copy_tree_r): Copy types if they are variably modified. + + * hooks.c (hook_tree_bool_false): New. + * hooks.h: Prototype it. + * langhooks.h (struct lang_hooks_for_tree_inlining): Add + var_mod_type_p. + * langhooks-def.h: Default for tree_inlining.var_mod_type_p is + hook_tree_bool_false. + + * tree.c (variably_modified_type_p): Moved here from + cp/tree.c. Use lang_hooks.tree_inlining.var_mod_type_p for + language-specific cases. Due to this, must weaken some 'if + and only if' checks to merely 'if'. + * tree.h: Prototype variably_modified_type_p. + 2002-10-22 Jim Wilson * config/i386/i386.md (subdi3_1): Add call to ix86_binary_operator_ok. diff --git a/gcc/c-objc-common.c b/gcc/c-objc-common.c index 43ec820599bc..d2bc5c1a391b 100644 --- a/gcc/c-objc-common.c +++ b/gcc/c-objc-common.c @@ -131,6 +131,22 @@ inline_forbidden_p (nodep, walk_subtrees, fn) break; + case RECORD_TYPE: + case UNION_TYPE: + /* We cannot inline a function of the form + + void F (int i) { struct S { int ar[i]; } s; } + + Attempting to do so produces a catch-22 in tree-inline.c. + If walk_tree examines the TYPE_FIELDS chain of RECORD_TYPE/ + UNION_TYPE nodes, then it goes into infinite recursion on a + structure containing a pointer to its own type. If it doesn't, + then the type node for S doesn't get adjusted properly when + F is inlined, and we abort in find_function_data. */ + for (t = TYPE_FIELDS (node); t; t = TREE_CHAIN (t)) + if (variably_modified_type_p (TREE_TYPE (t))) + return node; + default: break; } diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 068f43dd0f3c..90e209b52935 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,16 @@ +2002-10-25 Zack Weinberg + + PR middle-end/6994 + * cp-lang.c (cp_var_mod_type_p): New: C++ hook for + variably_modified_type_p. + * cp-tree.h: Remove prototype of variably_modified_type_p. + * tree.c (variably_modified_type_p): Remove; now implemented + in language-independent code. + + PR c++/7266 + * decl.c (grokdeclarator): Check that TREE_OPERAND 0 of a + SCOPE_REF is not null before dereferencing it. + 2002-10-24 David Edelsohn PR c++/7228 diff --git a/gcc/cp/cp-lang.c b/gcc/cp/cp-lang.c index b573cce317b1..1464ef6af19a 100644 --- a/gcc/cp/cp-lang.c +++ b/gcc/cp/cp-lang.c @@ -30,6 +30,7 @@ Boston, MA 02111-1307, USA. */ static HOST_WIDE_INT cxx_get_alias_set PARAMS ((tree)); static tree cp_expr_size PARAMS ((tree)); +static bool cp_var_mod_type_p PARAMS ((tree)); #undef LANG_HOOKS_NAME #define LANG_HOOKS_NAME "GNU C++" @@ -84,6 +85,8 @@ static tree cp_expr_size PARAMS ((tree)); cp_copy_res_decl_for_inlining #undef LANG_HOOKS_TREE_INLINING_ANON_AGGR_TYPE_P #define LANG_HOOKS_TREE_INLINING_ANON_AGGR_TYPE_P anon_aggr_type_p +#undef LANG_HOOKS_TREE_INLINING_VAR_MOD_TYPE_P +#define LANG_HOOKS_TREE_INLINING_VAR_MOD_TYPE_P cp_var_mod_type_p #undef LANG_HOOKS_TREE_INLINING_START_INLINING #define LANG_HOOKS_TREE_INLINING_START_INLINING cp_start_inlining #undef LANG_HOOKS_TREE_INLINING_END_INLINING @@ -130,3 +133,21 @@ cp_expr_size (exp) /* Use the default code. */ return lhd_expr_size (exp); } + +/* Returns true if T is a variably modified type, in the sense of C99. + This routine needs only check cases that cannot be handled by the + language-independent logic in tree-inline.c. */ + +static bool +cp_var_mod_type_p (tree 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))); + + /* All other types are not variably modified. */ + return false; +} + diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 77a066cc8c8e..9e8199f9faf8 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4213,7 +4213,6 @@ extern void end_input PARAMS ((void)); /* in tree.c */ 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 095008d1b784..5eb410ce53b5 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -11022,8 +11022,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist) pop_decl_namespace (); else if (friendp && (TREE_COMPLEXITY (declarator) < 2)) /* Don't fall out into global scope. Hides real bug? --eichin */ ; - else if (! IS_AGGR_TYPE_CODE - (TREE_CODE (TREE_OPERAND (declarator, 0)))) + else if (!TREE_OPERAND (declarator, 0) + || !IS_AGGR_TYPE_CODE + (TREE_CODE (TREE_OPERAND (declarator, 0)))) ; else if (TREE_COMPLEXITY (declarator) == current_class_depth) { diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 8868e6cf0b89..65dca0036066 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -1898,72 +1898,6 @@ 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/hooks.c b/gcc/hooks.c index 3fd876a208c0..2f71873e68cb 100644 --- a/gcc/hooks.c +++ b/gcc/hooks.c @@ -38,3 +38,11 @@ hook_void_bool_false () { return false; } + +/* Generic hook that takes (tree) and returns false. */ +bool +hook_tree_bool_false (a) + tree a ATTRIBUTE_UNUSED; +{ + return false; +} diff --git a/gcc/hooks.h b/gcc/hooks.h index 763ab8efc2ed..d91aca8474a0 100644 --- a/gcc/hooks.h +++ b/gcc/hooks.h @@ -24,5 +24,6 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. bool hook_void_bool_false PARAMS ((void)); void hook_void_void PARAMS ((void)); +bool hook_tree_bool_false PARAMS ((tree)); #endif diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h index e80b798798ae..013211746d1f 100644 --- a/gcc/langhooks-def.h +++ b/gcc/langhooks-def.h @@ -104,6 +104,8 @@ tree lhd_tree_inlining_convert_parm_for_inlining PARAMS ((tree, tree, tree)); lhd_tree_inlining_copy_res_decl_for_inlining #define LANG_HOOKS_TREE_INLINING_ANON_AGGR_TYPE_P \ lhd_tree_inlining_anon_aggr_type_p +#define LANG_HOOKS_TREE_INLINING_VAR_MOD_TYPE_P \ + hook_tree_bool_false #define LANG_HOOKS_TREE_INLINING_START_INLINING \ lhd_tree_inlining_start_inlining #define LANG_HOOKS_TREE_INLINING_END_INLINING \ @@ -120,6 +122,7 @@ tree lhd_tree_inlining_convert_parm_for_inlining PARAMS ((tree, tree, tree)); LANG_HOOKS_TREE_INLINING_AUTO_VAR_IN_FN_P, \ LANG_HOOKS_TREE_INLINING_COPY_RES_DECL_FOR_INLINING, \ LANG_HOOKS_TREE_INLINING_ANON_AGGR_TYPE_P, \ + LANG_HOOKS_TREE_INLINING_VAR_MOD_TYPE_P, \ LANG_HOOKS_TREE_INLINING_START_INLINING, \ LANG_HOOKS_TREE_INLINING_END_INLINING, \ LANG_HOOKS_TREE_INLINING_CONVERT_PARM_FOR_INLINING \ diff --git a/gcc/langhooks.h b/gcc/langhooks.h index 7a3c3bd0201e..a77ddeeb4d66 100644 --- a/gcc/langhooks.h +++ b/gcc/langhooks.h @@ -46,6 +46,7 @@ struct lang_hooks_for_tree_inlining void *, int *, void *)); int (*anon_aggr_type_p) PARAMS ((union tree_node *)); + bool (*var_mod_type_p) PARAMS ((union tree_node *)); int (*start_inlining) PARAMS ((union tree_node *)); void (*end_inlining) PARAMS ((union tree_node *)); union tree_node *(*convert_parm_for_inlining) PARAMS ((union tree_node *, diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ccd13075c7ae..40df0f47b12a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2002-10-25 Zack Weinberg + + * g++.dg/ext/vla1.C, gcc.dg/vla-2.c, + g++.dg/template/typename3.C: New tests. + 2002-10-24 Jakub Jelinek * gcc.c-torture/execute/20021024-1.c: New test. @@ -11,7 +16,7 @@ PR c++/7679 * g++.dg/parse/inline1.C: New test. - + 2002-10-22 Mark Mitchell PR c++/6579 diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 79f4c52f0b40..307c35c2bb1b 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -1224,6 +1224,12 @@ walk_tree (tp, func, data, htab_) { WALK_SUBTREE_TAIL (TREE_TYPE (*tp)); } + else if (TREE_CODE_CLASS (code) == 't') + { + WALK_SUBTREE (TYPE_SIZE (*tp)); + WALK_SUBTREE (TYPE_SIZE_UNIT (*tp)); + /* Also examine various special fields, below. */ + } result = (*lang_hooks.tree_inlining.walk_subtrees) (tp, &walk_subtrees, func, data, htab); @@ -1320,6 +1326,7 @@ walk_tree (tp, func, data, htab_) return NULL_TREE; #undef WALK_SUBTREE +#undef WALK_SUBTREE_TAIL } /* Like walk_tree, but does not walk duplicate nodes more than @@ -1378,8 +1385,8 @@ copy_tree_r (tp, walk_subtrees, data) if (TREE_CODE (*tp) == SCOPE_STMT) SCOPE_STMT_BLOCK (*tp) = NULL_TREE; } - else if (TREE_CODE_CLASS (code) == 't') - /* There's no need to copy types, or anything beneath them. */ + else if (TREE_CODE_CLASS (code) == 't' && !variably_modified_type_p (*tp)) + /* Types only need to be copied if they are variably modified. */ *walk_subtrees = 0; return NULL_TREE; diff --git a/gcc/tree.c b/gcc/tree.c index dd222a3b5df8..5ffb01006f63 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -4335,6 +4335,65 @@ int_fits_type_p (c, type) } } +/* Returns true if T is, contains, or refers to a type with variable + size. This concept is more general than that of C99 'variably + modified types': 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, and other languages may define similar constructs. */ + +bool +variably_modified_type_p (type) + 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 + the type pointed to is variably modified. */ + if ((TREE_CODE (type) == POINTER_TYPE + || TREE_CODE (type) == REFERENCE_TYPE) + && variably_modified_type_p (TREE_TYPE (type))) + return true; + + /* If TYPE is an array, it is variably modified if the array + elements are. (Note that the VLA case has already been checked + above.) */ + if (TREE_CODE (type) == ARRAY_TYPE + && variably_modified_type_p (TREE_TYPE (type))) + return true; + + /* 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; + } + + /* The current language may have other cases to check, but in general, + all other types are not variably modified. */ + return (*lang_hooks.tree_inlining.var_mod_type_p) (type); +} + /* Given a DECL or TYPE, return the scope in which it was declared, or NULL_TREE if there is no containing scope. */ diff --git a/gcc/tree.h b/gcc/tree.h index 084c3065cbd3..03724e1818a7 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -2938,6 +2938,7 @@ struct obstack; /* In tree.c */ extern int really_constant_p PARAMS ((tree)); extern int int_fits_type_p PARAMS ((tree, tree)); +extern bool variably_modified_type_p PARAMS ((tree)); extern int tree_log2 PARAMS ((tree)); extern int tree_floor_log2 PARAMS ((tree)); extern void preserve_data PARAMS ((void)); -- 2.47.2