Commit 5377d5ba by Richard Kenner Committed by Richard Kenner

langhooks-def.h (LANG_HOOKS_TREE_INLINING_VAR_MOD_TYPE_P): Extra arg.

	* langhooks-def.h (LANG_HOOKS_TREE_INLINING_VAR_MOD_TYPE_P): Extra arg.
	* langhooks.h (var_mod_type_p): Likewise.
	* c-decl.c (finish_decl): Add extra arg to variably_modified_type_p.
	* expr.c (count_type_elements): Properly handle return from
	array_type_nelts and properly test for overflow.
	* gimplify.c (gimplify_init_constructor): Properly handle return
	from array_type_nelts.
	(gimplify_addr_expr): Remove redundant clear of TREE_SIDE_EFFECTS.
	* integrate.c (copy_decl_for_inlining): Correct comments.
	* tree-inline.c (remap_decl): Update comments, remove dead code,
	and copy DECL_FIELD_OFFSET and DECL_QUALIFIER, if they exist.
	(remap_type): Only remap if variably modified by vars in function
	being inlined.
	(copy_body_r): Use compatible_type langhooks to see when can fold.
	(setup_one_parameter): Don't remap type.
	(inline_forbidden_p_1): Add arg to variably_modified_type_p.
	* tree.c (recompute_tree_invarant_for_addr_expr): Properly
	compute TREE_INVARIANT for decl case.
	(find_var_from_fn): New function.
	(variably_modified_type_p): Add arg and call new function.
	* tree.h (variably_modified_type_p): Add extra arg.

	* cp/cp-lang.c (cp_var_mod_type_p): Add extra arg.
	* cp/decl.c (grokdeclarator): Extra arg to variably_modified_type_p.
	* cp/pt.c (check_instantiated_args, unify): Likewise.

From-SVN: r84144
parent aac1d259
2004-07-05 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
* langhooks-def.h (LANG_HOOKS_TREE_INLINING_VAR_MOD_TYPE_P): Extra arg.
* langhooks.h (var_mod_type_p): Likewise.
* c-decl.c (finish_decl): Add extra arg to variably_modified_type_p.
* expr.c (count_type_elements): Properly handle return from
array_type_nelts and properly test for overflow.
* gimplify.c (gimplify_init_constructor): Properly handle return
from array_type_nelts.
(gimplify_addr_expr): Remove redundant clear of TREE_SIDE_EFFECTS.
* integrate.c (copy_decl_for_inlining): Correct comments.
* tree-inline.c (remap_decl): Update comments, remove dead code,
and copy DECL_FIELD_OFFSET and DECL_QUALIFIER, if they exist.
(remap_type): Only remap if variably modified by vars in function
being inlined.
(copy_body_r): Use compatible_type langhooks to see when can fold.
(setup_one_parameter): Don't remap type.
(inline_forbidden_p_1): Add arg to variably_modified_type_p.
* tree.c (recompute_tree_invarant_for_addr_expr): Properly
compute TREE_INVARIANT for decl case.
(find_var_from_fn): New function.
(variably_modified_type_p): Add arg and call new function.
* tree.h (variably_modified_type_p): Add extra arg.
2004-07-05 Eric Botcazou <ebotcazou@libertysurf.fr> 2004-07-05 Eric Botcazou <ebotcazou@libertysurf.fr>
* config/sparc/sparc.md (nonlocal_goto): Remove disabled code. * config/sparc/sparc.md (nonlocal_goto): Remove disabled code.
......
...@@ -3037,7 +3037,7 @@ finish_decl (tree decl, tree init, tree asmspec_tree) ...@@ -3037,7 +3037,7 @@ finish_decl (tree decl, tree init, tree asmspec_tree)
if (TREE_CODE (decl) == TYPE_DECL) if (TREE_CODE (decl) == TYPE_DECL)
{ {
if (!DECL_FILE_SCOPE_P (decl) if (!DECL_FILE_SCOPE_P (decl)
&& variably_modified_type_p (TREE_TYPE (decl))) && variably_modified_type_p (TREE_TYPE (decl), NULL_TREE))
add_stmt (build_stmt (DECL_EXPR, decl)); add_stmt (build_stmt (DECL_EXPR, decl));
rest_of_decl_compilation (decl, NULL, DECL_FILE_SCOPE_P (decl), 0); rest_of_decl_compilation (decl, NULL, DECL_FILE_SCOPE_P (decl), 0);
......
2004-07-05 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
* cp-lang.c (cp_var_mod_type_p): Add extra arg.
* decl.c (grokdeclarator): Extra arg to variably_modified_type_p.
* pt.c (check_instantiated_args, unify): Likewise.
2004-07-05 Phil Edwards <phil@codesourcery.com> 2004-07-05 Phil Edwards <phil@codesourcery.com>
* Make-lang.in (check-c++, lang_checks): Add some comments. * Make-lang.in (check-c++, lang_checks): Add some comments.
......
...@@ -38,7 +38,7 @@ static HOST_WIDE_INT cxx_get_alias_set (tree); ...@@ -38,7 +38,7 @@ static HOST_WIDE_INT cxx_get_alias_set (tree);
static bool cxx_warn_unused_global_decl (tree); static bool cxx_warn_unused_global_decl (tree);
static tree cp_expr_size (tree); static tree cp_expr_size (tree);
static size_t cp_tree_size (enum tree_code); static size_t cp_tree_size (enum tree_code);
static bool cp_var_mod_type_p (tree); static bool cp_var_mod_type_p (tree, tree);
static int cxx_types_compatible_p (tree, tree); static int cxx_types_compatible_p (tree, tree);
static void cxx_initialize_diagnostics (diagnostic_context *); static void cxx_initialize_diagnostics (diagnostic_context *);
...@@ -307,17 +307,19 @@ cp_tree_size (enum tree_code code) ...@@ -307,17 +307,19 @@ cp_tree_size (enum tree_code code)
} }
/* Returns true if T is a variably modified type, in the sense of C99. /* Returns true if T is a variably modified type, in the sense of C99.
FN is as passed to variably_modified_p.
This routine needs only check cases that cannot be handled by the This routine needs only check cases that cannot be handled by the
language-independent logic in tree-inline.c. */ language-independent logic in tree.c. */
static bool static bool
cp_var_mod_type_p (tree type) cp_var_mod_type_p (tree type, tree fn)
{ {
/* If TYPE is a pointer-to-member, it is variably modified if either /* If TYPE is a pointer-to-member, it is variably modified if either
the class or the member are variably modified. */ the class or the member are variably modified. */
if (TYPE_PTR_TO_MEMBER_P (type)) if (TYPE_PTR_TO_MEMBER_P (type))
return (variably_modified_type_p (TYPE_PTRMEM_CLASS_TYPE (type)) return (variably_modified_type_p (TYPE_PTRMEM_CLASS_TYPE (type), fn)
|| variably_modified_type_p (TYPE_PTRMEM_POINTED_TO_TYPE (type))); || variably_modified_type_p (TYPE_PTRMEM_POINTED_TO_TYPE (type),
fn));
/* All other types are not variably modified. */ /* All other types are not variably modified. */
return false; return false;
......
...@@ -7329,7 +7329,7 @@ grokdeclarator (const cp_declarator *declarator, ...@@ -7329,7 +7329,7 @@ grokdeclarator (const cp_declarator *declarator,
if ((decl_context == FIELD || decl_context == PARM) if ((decl_context == FIELD || decl_context == PARM)
&& !processing_template_decl && !processing_template_decl
&& variably_modified_type_p (type)) && variably_modified_type_p (type, NULL_TREE))
{ {
if (decl_context == FIELD) if (decl_context == FIELD)
error ("data member may not have variably modified type `%T'", type); error ("data member may not have variably modified type `%T'", type);
......
...@@ -8557,7 +8557,7 @@ check_instantiated_args (tree tmpl, tree args, tsubst_flags_t complain) ...@@ -8557,7 +8557,7 @@ check_instantiated_args (tree tmpl, tree args, tsubst_flags_t complain)
} }
/* In order to avoid all sorts of complications, we do not /* In order to avoid all sorts of complications, we do not
allow variably-modified types as template arguments. */ allow variably-modified types as template arguments. */
else if (variably_modified_type_p (t)) else if (variably_modified_type_p (t, NULL_TREE))
{ {
if (complain & tf_error) if (complain & tf_error)
error ("`%T' is a variably modified type", t); error ("`%T' is a variably modified type", t);
...@@ -9732,7 +9732,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) ...@@ -9732,7 +9732,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
the bound of the array will not be computable in an the bound of the array will not be computable in an
instantiation. Besides, such types are not allowed in instantiation. Besides, such types are not allowed in
ISO C++, so we can do as we please here. */ ISO C++, so we can do as we please here. */
if (variably_modified_type_p (arg)) if (variably_modified_type_p (arg, NULL_TREE))
return 1; return 1;
} }
......
...@@ -4497,11 +4497,11 @@ count_type_elements (tree type) ...@@ -4497,11 +4497,11 @@ count_type_elements (tree type)
tree telts = array_type_nelts (type); tree telts = array_type_nelts (type);
if (telts && host_integerp (telts, 1)) if (telts && host_integerp (telts, 1))
{ {
HOST_WIDE_INT n = tree_low_cst (telts, 1); HOST_WIDE_INT n = tree_low_cst (telts, 1) + 1;
HOST_WIDE_INT m = count_type_elements (TREE_TYPE (type)); HOST_WIDE_INT m = count_type_elements (TREE_TYPE (type));
if (n == 0) if (n == 0)
return 0; return 0;
if (max / n < m) else if (max / n > m)
return n * m; return n * m;
} }
return -1; return -1;
......
...@@ -2514,7 +2514,7 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p, ...@@ -2514,7 +2514,7 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
{ {
tree nelts = array_type_nelts (type); tree nelts = array_type_nelts (type);
if (!host_integerp (nelts, 1) if (!host_integerp (nelts, 1)
|| tree_low_cst (nelts, 1) != len) || tree_low_cst (nelts, 1) + 1 != len)
cleared = 1;; cleared = 1;;
} }
else if (len != fields_length (type)) else if (len != fields_length (type))
...@@ -3050,12 +3050,8 @@ gimplify_addr_expr (tree *expr_p, tree *pre_p, tree *post_p) ...@@ -3050,12 +3050,8 @@ gimplify_addr_expr (tree *expr_p, tree *pre_p, tree *post_p)
is_gimple_addr_expr_arg, fb_either); is_gimple_addr_expr_arg, fb_either);
if (ret != GS_ERROR) if (ret != GS_ERROR)
{ {
/* At this point, the argument of the ADDR_EXPR should be /* Make sure TREE_INVARIANT, TREE_CONSTANT, and TREE_SIDE_EFFECTS
sufficiently simple that there are never side effects. */ is set properly. */
/* ??? Could split out the decision code from build1 to verify. */
TREE_SIDE_EFFECTS (expr) = 0;
/* Make sure TREE_INVARIANT/TREE_CONSTANT is set properly. */
recompute_tree_invarant_for_addr_expr (expr); recompute_tree_invarant_for_addr_expr (expr);
/* Mark the RHS addressable. */ /* Mark the RHS addressable. */
......
...@@ -105,9 +105,8 @@ function_attribute_inlinable_p (tree fndecl) ...@@ -105,9 +105,8 @@ function_attribute_inlinable_p (tree fndecl)
return true; return true;
} }
/* Copy NODE (which must be a DECL, but not a PARM_DECL). The DECL /* Copy NODE (which must be a DECL). The DECL originally was in the FROM_FN,
originally was in the FROM_FN, but now it will be in the but now it will be in the TO_FN. */
TO_FN. */
tree tree
copy_decl_for_inlining (tree decl, tree from_fn, tree to_fn) copy_decl_for_inlining (tree decl, tree from_fn, tree to_fn)
...@@ -132,7 +131,7 @@ copy_decl_for_inlining (tree decl, tree from_fn, tree to_fn) ...@@ -132,7 +131,7 @@ copy_decl_for_inlining (tree decl, tree from_fn, tree to_fn)
else else
type = TREE_TYPE (decl); type = TREE_TYPE (decl);
/* For a parameter, we must make an equivalent VAR_DECL, not a /* For a parameter or result, we must make an equivalent VAR_DECL, not a
new PARM_DECL. */ new PARM_DECL. */
copy = build_decl (VAR_DECL, DECL_NAME (decl), type); copy = build_decl (VAR_DECL, DECL_NAME (decl), type);
if (!invisiref) if (!invisiref)
......
...@@ -157,7 +157,7 @@ extern int lhd_gimplify_expr (tree *, tree *, tree *); ...@@ -157,7 +157,7 @@ extern int lhd_gimplify_expr (tree *, tree *, tree *);
#define LANG_HOOKS_TREE_INLINING_ANON_AGGR_TYPE_P \ #define LANG_HOOKS_TREE_INLINING_ANON_AGGR_TYPE_P \
lhd_tree_inlining_anon_aggr_type_p lhd_tree_inlining_anon_aggr_type_p
#define LANG_HOOKS_TREE_INLINING_VAR_MOD_TYPE_P \ #define LANG_HOOKS_TREE_INLINING_VAR_MOD_TYPE_P \
hook_bool_tree_false hook_bool_tree_tree_false
#define LANG_HOOKS_TREE_INLINING_START_INLINING \ #define LANG_HOOKS_TREE_INLINING_START_INLINING \
lhd_tree_inlining_start_inlining lhd_tree_inlining_start_inlining
#define LANG_HOOKS_TREE_INLINING_END_INLINING \ #define LANG_HOOKS_TREE_INLINING_END_INLINING \
......
...@@ -43,7 +43,7 @@ struct lang_hooks_for_tree_inlining ...@@ -43,7 +43,7 @@ struct lang_hooks_for_tree_inlining
tree (*copy_res_decl_for_inlining) (tree, tree, tree, tree (*copy_res_decl_for_inlining) (tree, tree, tree,
void *, int *, tree); void *, int *, tree);
int (*anon_aggr_type_p) (tree); int (*anon_aggr_type_p) (tree);
bool (*var_mod_type_p) (tree); bool (*var_mod_type_p) (tree, tree);
int (*start_inlining) (tree); int (*start_inlining) (tree);
void (*end_inlining) (tree); void (*end_inlining) (tree);
tree (*convert_parm_for_inlining) (tree, tree, tree, int); tree (*convert_parm_for_inlining) (tree, tree, tree, int);
......
...@@ -155,35 +155,21 @@ insert_decl_map (inline_data *id, tree key, tree value) ...@@ -155,35 +155,21 @@ insert_decl_map (inline_data *id, tree key, tree value)
(splay_tree_value) value); (splay_tree_value) value);
} }
/* Remap DECL during the copying of the BLOCK tree for the function. */ /* Remap DECL during the copying of the BLOCK tree for the function.
We are only called to remap local variables in the current function. */
static tree static tree
remap_decl (tree decl, inline_data *id) remap_decl (tree decl, inline_data *id)
{ {
splay_tree_node n; splay_tree_node n = splay_tree_lookup (id->decl_map, (splay_tree_key) decl);
tree fn; tree fn = VARRAY_TOP_TREE (id->fns);
/* We only remap local variables in the current function. */
fn = VARRAY_TOP_TREE (id->fns);
#if 0
/* We need to remap statics, too, so that they get expanded even if the
inline function is never emitted out of line. We might as well also
remap extern decls so that they show up in the debug info. */
if (! lang_hooks.tree_inlining.auto_var_in_fn_p (decl, fn))
return NULL_TREE;
#endif
/* See if we have remapped this declaration. */
n = splay_tree_lookup (id->decl_map, (splay_tree_key) decl);
/* If we didn't already have an equivalent for this declaration, /* See if we have remapped this declaration. If we didn't already have an
create one now. */ equivalent for this declaration, create one now. */
if (!n) if (!n)
{ {
tree t;
/* Make a copy of the variable or label. */ /* Make a copy of the variable or label. */
t = copy_decl_for_inlining (decl, fn, VARRAY_TREE (id->fns, 0)); tree t = copy_decl_for_inlining (decl, fn, VARRAY_TREE (id->fns, 0));
/* Remap types, if necessary. */ /* Remap types, if necessary. */
TREE_TYPE (t) = remap_type (TREE_TYPE (t), id); TREE_TYPE (t) = remap_type (TREE_TYPE (t), id);
...@@ -197,6 +183,14 @@ remap_decl (tree decl, inline_data *id) ...@@ -197,6 +183,14 @@ remap_decl (tree decl, inline_data *id)
walk_tree (&DECL_SIZE (t), copy_body_r, id, NULL); walk_tree (&DECL_SIZE (t), copy_body_r, id, NULL);
walk_tree (&DECL_SIZE_UNIT (t), copy_body_r, id, NULL); walk_tree (&DECL_SIZE_UNIT (t), copy_body_r, id, NULL);
/* If fields, do likewise for offset and qualifier. */
if (TREE_CODE (t) == FIELD_DECL)
{
walk_tree (&DECL_FIELD_OFFSET (t), copy_body_r, id, NULL);
if (TREE_CODE (DECL_CONTEXT (t)) == QUAL_UNION_TYPE)
walk_tree (&DECL_QUALIFIER (t), copy_body_r, id, NULL);
}
#if 0 #if 0
/* FIXME handle anon aggrs. */ /* FIXME handle anon aggrs. */
if (! DECL_NAME (t) && TREE_TYPE (t) if (! DECL_NAME (t) && TREE_TYPE (t)
...@@ -243,8 +237,9 @@ remap_type (tree type, inline_data *id) ...@@ -243,8 +237,9 @@ remap_type (tree type, inline_data *id)
if (node) if (node)
return (tree) node->value; return (tree) node->value;
/* The type only needs remapping if it's variably modified. */ /* The type only needs remapping if it's variably modified by a variable
if (! variably_modified_type_p (type)) in the function we are inlining. */
if (! variably_modified_type_p (type, VARRAY_TOP_TREE (id->fns)))
{ {
insert_decl_map (id, type, type); insert_decl_map (id, type, type);
return type; return type;
...@@ -458,12 +453,8 @@ copy_bind_expr (tree *tp, int *walk_subtrees, inline_data *id) ...@@ -458,12 +453,8 @@ copy_bind_expr (tree *tp, int *walk_subtrees, inline_data *id)
static tree static tree
copy_body_r (tree *tp, int *walk_subtrees, void *data) copy_body_r (tree *tp, int *walk_subtrees, void *data)
{ {
inline_data* id; inline_data *id = (inline_data *) data;
tree fn; tree fn = VARRAY_TOP_TREE (id->fns);
/* Set up. */
id = (inline_data *) data;
fn = VARRAY_TOP_TREE (id->fns);
#if 0 #if 0
/* All automatic variables should have a DECL_CONTEXT indicating /* All automatic variables should have a DECL_CONTEXT indicating
...@@ -507,7 +498,7 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data) ...@@ -507,7 +498,7 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
/* Local variables and labels need to be replaced by equivalent /* Local variables and labels need to be replaced by equivalent
variables. We don't want to copy static variables; there's only variables. We don't want to copy static variables; there's only
one of those, no matter how many times we inline the containing one of those, no matter how many times we inline the containing
function. */ function. Similarly for globals from an outer function. */
else if (lang_hooks.tree_inlining.auto_var_in_fn_p (*tp, fn)) else if (lang_hooks.tree_inlining.auto_var_in_fn_p (*tp, fn))
{ {
tree new_decl; tree new_decl;
...@@ -603,13 +594,13 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data) ...@@ -603,13 +594,13 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
value = (tree) n->value; value = (tree) n->value;
if (TREE_CODE (value) == INDIRECT_REF) if (TREE_CODE (value) == INDIRECT_REF)
{ {
/* Assume that the argument types properly match the if (!lang_hooks.types_compatible_p
parameter types. We can't compare them well enough (TREE_TYPE (*tp), TREE_TYPE (TREE_OPERAND (value, 0))))
without a comptypes langhook, and we don't want to *tp = fold_convert (TREE_TYPE (*tp),
call convert and introduce a NOP_EXPR to convert TREE_OPERAND (value, 0));
between two equivalent types (i.e. that only differ else
in use of typedef names). */ *tp = TREE_OPERAND (value, 0);
*tp = TREE_OPERAND (value, 0);
return copy_body_r (tp, walk_subtrees, data); return copy_body_r (tp, walk_subtrees, data);
} }
} }
...@@ -626,7 +617,9 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data) ...@@ -626,7 +617,9 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
{ {
value = (tree) n->value; value = (tree) n->value;
STRIP_NOPS (value); STRIP_NOPS (value);
if (TREE_CODE (value) == ADDR_EXPR) if (TREE_CODE (value) == ADDR_EXPR
&& (lang_hooks.types_compatible_p
(TREE_TYPE (*tp), TREE_TYPE (TREE_OPERAND (value, 0)))))
{ {
*tp = TREE_OPERAND (value, 0); *tp = TREE_OPERAND (value, 0);
return copy_body_r (tp, walk_subtrees, data); return copy_body_r (tp, walk_subtrees, data);
...@@ -739,9 +732,10 @@ setup_one_parameter (inline_data *id, tree p, tree value, tree fn, ...@@ -739,9 +732,10 @@ setup_one_parameter (inline_data *id, tree p, tree value, tree fn,
} }
} }
/* Make an equivalent VAR_DECL with the remapped type. */ /* Make an equivalent VAR_DECL. Note that we must NOT remap the type
here since the type of this decl must be visible to the calling
function. */
var = copy_decl_for_inlining (p, fn, VARRAY_TREE (id->fns, 0)); var = copy_decl_for_inlining (p, fn, VARRAY_TREE (id->fns, 0));
TREE_TYPE (var) = remap_type (TREE_TYPE (var), id);
/* See if the frontend wants to pass this by invisible reference. If /* See if the frontend wants to pass this by invisible reference. If
so, our new VAR_DECL will have REFERENCE_TYPE, and we need to so, our new VAR_DECL will have REFERENCE_TYPE, and we need to
...@@ -1072,7 +1066,7 @@ inline_forbidden_p_1 (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED, ...@@ -1072,7 +1066,7 @@ inline_forbidden_p_1 (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED,
then the type node for S doesn't get adjusted properly when then the type node for S doesn't get adjusted properly when
F is inlined, and we abort in find_function_data. */ F is inlined, and we abort in find_function_data. */
for (t = TYPE_FIELDS (node); t; t = TREE_CHAIN (t)) for (t = TYPE_FIELDS (node); t; t = TREE_CHAIN (t))
if (variably_modified_type_p (TREE_TYPE (t))) if (variably_modified_type_p (TREE_TYPE (t), NULL))
{ {
inline_forbidden_reason inline_forbidden_reason
= N_("%Jfunction '%F' can never be inlined " = N_("%Jfunction '%F' can never be inlined "
......
...@@ -2352,16 +2352,20 @@ do { tree _node = (NODE); \ ...@@ -2352,16 +2352,20 @@ do { tree _node = (NODE); \
} }
/* Now see what's inside. If it's an INDIRECT_REF, copy our properties from /* Now see what's inside. If it's an INDIRECT_REF, copy our properties from
it. If it's a decl, it's definitely invariant and it's constant if the it. If it's a decl, it's invariant and constant if the decl is static.
decl is static. (Taking the address of a volatile variable is not It's also invariant if it's a decl in the current function. (Taking the
volatile.) If it's a constant, the address is both invariant and address of a volatile variable is not volatile.) If it's a constant,
constant. Otherwise it's neither. */ the address is both invariant and constant. Otherwise it's neither. */
if (TREE_CODE (node) == INDIRECT_REF) if (TREE_CODE (node) == INDIRECT_REF)
UPDATE_TITCSE (node); UPDATE_TITCSE (node);
else if (DECL_P (node)) else if (DECL_P (node))
{ {
if (!staticp (node)) if (staticp (node))
;
else if (decl_function_context (node) == current_function_decl)
tc = false; tc = false;
else
ti = tc = false;
} }
else if (TREE_CODE_CLASS (TREE_CODE (node)) == 'c') else if (TREE_CODE_CLASS (TREE_CODE (node)) == 'c')
; ;
...@@ -4685,21 +4689,50 @@ int_fits_type_p (tree c, tree type) ...@@ -4685,21 +4689,50 @@ int_fits_type_p (tree c, tree type)
} }
} }
/* Subprogram of following function. Called by walk_tree.
Return *TP if it is an automatic variable or parameter of the
function passed in as DATA. */
static tree
find_var_from_fn (tree *tp, int *walk_subtrees, void *data)
{
tree fn = (tree) data;
if (TYPE_P (*tp))
*walk_subtrees = 0;
else if (DECL_P (*tp) && lang_hooks.tree_inlining.auto_var_in_fn_p (*tp, fn))
return *tp;
return NULL_TREE;
}
/* Returns true if T is, contains, or refers to a type with variable /* Returns true if T is, contains, or refers to a type with variable
size. This concept is more general than that of C99 'variably size. If FN is nonzero, only return true if a modifier of the type
modified types': in C99, a struct type is never variably modified or position of FN is a variable or parameter inside FN.
because a VLA may not appear as a structure member. However, in
GNU C code like: 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()]; }; struct S { int i[f()]; };
is valid, and other languages may define similar constructs. */ is valid, and other languages may define similar constructs. */
bool bool
variably_modified_type_p (tree type) variably_modified_type_p (tree type, tree fn)
{ {
tree t; tree t;
/* Test if T is either variable (if FN is zero) or an expression containing
a variable in FN. */
#define RETURN_TRUE_IF_VAR(T) \
do { tree _t = (T); \
if (_t && _t != error_mark_node && TREE_CODE (_t) != INTEGER_CST \
&& (!fn || walk_tree (&_t, find_var_from_fn, fn, NULL))) \
return true; } while (0)
if (type == error_mark_node) if (type == error_mark_node)
return false; return false;
...@@ -4708,9 +4741,8 @@ variably_modified_type_p (tree type) ...@@ -4708,9 +4741,8 @@ variably_modified_type_p (tree type)
We do not yet have a representation of the C99 '[*]' syntax. We do not yet have a representation of the C99 '[*]' syntax.
When a representation is chosen, this function should be modified When a representation is chosen, this function should be modified
to test for that case as well. */ to test for that case as well. */
t = TYPE_SIZE (type); RETURN_TRUE_IF_VAR (TYPE_SIZE (type));
if (t && t != error_mark_node && TREE_CODE (t) != INTEGER_CST) RETURN_TRUE_IF_VAR (TYPE_SIZE_UNIT(type));
return true;
switch (TREE_CODE (type)) switch (TREE_CODE (type))
{ {
...@@ -4719,7 +4751,7 @@ variably_modified_type_p (tree type) ...@@ -4719,7 +4751,7 @@ variably_modified_type_p (tree type)
case ARRAY_TYPE: case ARRAY_TYPE:
case SET_TYPE: case SET_TYPE:
case VECTOR_TYPE: case VECTOR_TYPE:
if (variably_modified_type_p (TREE_TYPE (type))) if (variably_modified_type_p (TREE_TYPE (type), fn))
return true; return true;
break; break;
...@@ -4727,13 +4759,13 @@ variably_modified_type_p (tree type) ...@@ -4727,13 +4759,13 @@ variably_modified_type_p (tree type)
case METHOD_TYPE: case METHOD_TYPE:
/* If TYPE is a function type, it is variably modified if any of the /* If TYPE is a function type, it is variably modified if any of the
parameters or the return type are variably modified. */ parameters or the return type are variably modified. */
if (variably_modified_type_p (TREE_TYPE (type))) if (variably_modified_type_p (TREE_TYPE (type), fn))
return true; return true;
for (t = TYPE_ARG_TYPES (type); for (t = TYPE_ARG_TYPES (type);
t && t != void_list_node; t && t != void_list_node;
t = TREE_CHAIN (t)) t = TREE_CHAIN (t))
if (variably_modified_type_p (TREE_VALUE (t))) if (variably_modified_type_p (TREE_VALUE (t), fn))
return true; return true;
break; break;
...@@ -4744,13 +4776,8 @@ variably_modified_type_p (tree type) ...@@ -4744,13 +4776,8 @@ variably_modified_type_p (tree type)
case CHAR_TYPE: case CHAR_TYPE:
/* Scalar types are variably modified if their end points /* Scalar types are variably modified if their end points
aren't constant. */ aren't constant. */
t = TYPE_MIN_VALUE (type); RETURN_TRUE_IF_VAR (TYPE_MIN_VALUE (type));
if (t && t != error_mark_node && TREE_CODE (t) != INTEGER_CST) RETURN_TRUE_IF_VAR (TYPE_MAX_VALUE (type));
return true;
t = TYPE_MAX_VALUE (type);
if (t && t != error_mark_node && TREE_CODE (t) != INTEGER_CST)
return true;
break; break;
case RECORD_TYPE: case RECORD_TYPE:
...@@ -4763,14 +4790,12 @@ variably_modified_type_p (tree type) ...@@ -4763,14 +4790,12 @@ variably_modified_type_p (tree type)
for (t = TYPE_FIELDS (type); t; t = TREE_CHAIN (t)) for (t = TYPE_FIELDS (type); t; t = TREE_CHAIN (t))
if (TREE_CODE (t) == FIELD_DECL) if (TREE_CODE (t) == FIELD_DECL)
{ {
tree t1 = DECL_FIELD_OFFSET (t); RETURN_TRUE_IF_VAR (DECL_FIELD_OFFSET (t));
RETURN_TRUE_IF_VAR (DECL_SIZE (t));
RETURN_TRUE_IF_VAR (DECL_SIZE_UNIT (t));
if (t1 && t1 != error_mark_node && TREE_CODE (t1) != INTEGER_CST) if (TREE_CODE (type) == QUAL_UNION_TYPE)
return true; RETURN_TRUE_IF_VAR (DECL_QUALIFIER (t));
t1 = DECL_SIZE (t);
if (t1 && t1 != error_mark_node && TREE_CODE (t1) != INTEGER_CST)
return true;
} }
break; break;
...@@ -4780,7 +4805,9 @@ variably_modified_type_p (tree type) ...@@ -4780,7 +4805,9 @@ variably_modified_type_p (tree type)
/* The current language may have other cases to check, but in general, /* The current language may have other cases to check, but in general,
all other types are not variably modified. */ all other types are not variably modified. */
return lang_hooks.tree_inlining.var_mod_type_p (type); return lang_hooks.tree_inlining.var_mod_type_p (type, fn);
#undef RETURN_TRUE_IF_VAR
} }
/* Given a DECL or TYPE, return the scope in which it was declared, or /* Given a DECL or TYPE, return the scope in which it was declared, or
......
...@@ -3469,7 +3469,7 @@ extern int objects_must_conflict_p (tree, tree); ...@@ -3469,7 +3469,7 @@ extern int objects_must_conflict_p (tree, tree);
/* In tree.c */ /* In tree.c */
extern int really_constant_p (tree); extern int really_constant_p (tree);
extern int int_fits_type_p (tree, tree); extern int int_fits_type_p (tree, tree);
extern bool variably_modified_type_p (tree); extern bool variably_modified_type_p (tree, tree);
extern int tree_log2 (tree); extern int tree_log2 (tree);
extern int tree_floor_log2 (tree); extern int tree_floor_log2 (tree);
extern int simple_cst_equal (tree, tree); extern int simple_cst_equal (tree, tree);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment