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>
* config/sparc/sparc.md (nonlocal_goto): Remove disabled code.
......
......@@ -3037,7 +3037,7 @@ finish_decl (tree decl, tree init, tree asmspec_tree)
if (TREE_CODE (decl) == TYPE_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));
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>
* Make-lang.in (check-c++, lang_checks): Add some comments.
......
......@@ -38,7 +38,7 @@ static HOST_WIDE_INT cxx_get_alias_set (tree);
static bool cxx_warn_unused_global_decl (tree);
static tree cp_expr_size (tree);
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 void cxx_initialize_diagnostics (diagnostic_context *);
......@@ -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.
FN is as passed to variably_modified_p.
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
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
the class or the member are variably modified. */
if (TYPE_PTR_TO_MEMBER_P (type))
return (variably_modified_type_p (TYPE_PTRMEM_CLASS_TYPE (type))
|| variably_modified_type_p (TYPE_PTRMEM_POINTED_TO_TYPE (type)));
return (variably_modified_type_p (TYPE_PTRMEM_CLASS_TYPE (type), fn)
|| variably_modified_type_p (TYPE_PTRMEM_POINTED_TO_TYPE (type),
fn));
/* All other types are not variably modified. */
return false;
......
......@@ -7329,7 +7329,7 @@ grokdeclarator (const cp_declarator *declarator,
if ((decl_context == FIELD || decl_context == PARM)
&& !processing_template_decl
&& variably_modified_type_p (type))
&& variably_modified_type_p (type, NULL_TREE))
{
if (decl_context == FIELD)
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)
}
/* In order to avoid all sorts of complications, we do not
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)
error ("`%T' is a variably modified type", t);
......@@ -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
instantiation. Besides, such types are not allowed in
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;
}
......
......@@ -4497,11 +4497,11 @@ count_type_elements (tree type)
tree telts = array_type_nelts (type);
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));
if (n == 0)
return 0;
if (max / n < m)
else if (max / n > m)
return n * m;
}
return -1;
......
......@@ -2514,7 +2514,7 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
{
tree nelts = array_type_nelts (type);
if (!host_integerp (nelts, 1)
|| tree_low_cst (nelts, 1) != len)
|| tree_low_cst (nelts, 1) + 1 != len)
cleared = 1;;
}
else if (len != fields_length (type))
......@@ -3050,12 +3050,8 @@ gimplify_addr_expr (tree *expr_p, tree *pre_p, tree *post_p)
is_gimple_addr_expr_arg, fb_either);
if (ret != GS_ERROR)
{
/* At this point, the argument of the ADDR_EXPR should be
sufficiently simple that there are never side effects. */
/* ??? Could split out the decision code from build1 to verify. */
TREE_SIDE_EFFECTS (expr) = 0;
/* Make sure TREE_INVARIANT/TREE_CONSTANT is set properly. */
/* Make sure TREE_INVARIANT, TREE_CONSTANT, and TREE_SIDE_EFFECTS
is set properly. */
recompute_tree_invarant_for_addr_expr (expr);
/* Mark the RHS addressable. */
......
......@@ -105,9 +105,8 @@ function_attribute_inlinable_p (tree fndecl)
return true;
}
/* Copy NODE (which must be a DECL, but not a PARM_DECL). The DECL
originally was in the FROM_FN, but now it will be in the
TO_FN. */
/* Copy NODE (which must be a DECL). The DECL originally was in the FROM_FN,
but now it will be in the TO_FN. */
tree
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
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. */
copy = build_decl (VAR_DECL, DECL_NAME (decl), type);
if (!invisiref)
......
......@@ -157,7 +157,7 @@ extern int lhd_gimplify_expr (tree *, tree *, tree *);
#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_bool_tree_false
hook_bool_tree_tree_false
#define LANG_HOOKS_TREE_INLINING_START_INLINING \
lhd_tree_inlining_start_inlining
#define LANG_HOOKS_TREE_INLINING_END_INLINING \
......
......@@ -43,7 +43,7 @@ struct lang_hooks_for_tree_inlining
tree (*copy_res_decl_for_inlining) (tree, tree, tree,
void *, int *, tree);
int (*anon_aggr_type_p) (tree);
bool (*var_mod_type_p) (tree);
bool (*var_mod_type_p) (tree, tree);
int (*start_inlining) (tree);
void (*end_inlining) (tree);
tree (*convert_parm_for_inlining) (tree, tree, tree, int);
......
......@@ -155,35 +155,21 @@ insert_decl_map (inline_data *id, tree key, tree 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
remap_decl (tree decl, inline_data *id)
{
splay_tree_node n;
tree fn;
/* 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);
splay_tree_node n = splay_tree_lookup (id->decl_map, (splay_tree_key) decl);
tree fn = VARRAY_TOP_TREE (id->fns);
/* If we didn't already have an equivalent for this declaration,
create one now. */
/* See if we have remapped this declaration. If we didn't already have an
equivalent for this declaration, create one now. */
if (!n)
{
tree t;
/* 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. */
TREE_TYPE (t) = remap_type (TREE_TYPE (t), 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_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
/* FIXME handle anon aggrs. */
if (! DECL_NAME (t) && TREE_TYPE (t)
......@@ -243,8 +237,9 @@ remap_type (tree type, inline_data *id)
if (node)
return (tree) node->value;
/* The type only needs remapping if it's variably modified. */
if (! variably_modified_type_p (type))
/* The type only needs remapping if it's variably modified by a variable
in the function we are inlining. */
if (! variably_modified_type_p (type, VARRAY_TOP_TREE (id->fns)))
{
insert_decl_map (id, type, type);
return type;
......@@ -458,12 +453,8 @@ copy_bind_expr (tree *tp, int *walk_subtrees, inline_data *id)
static tree
copy_body_r (tree *tp, int *walk_subtrees, void *data)
{
inline_data* id;
tree fn;
/* Set up. */
id = (inline_data *) data;
fn = VARRAY_TOP_TREE (id->fns);
inline_data *id = (inline_data *) data;
tree fn = VARRAY_TOP_TREE (id->fns);
#if 0
/* All automatic variables should have a DECL_CONTEXT indicating
......@@ -507,7 +498,7 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
/* Local variables and labels need to be replaced by equivalent
variables. We don't want to copy static variables; there's only
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))
{
tree new_decl;
......@@ -603,13 +594,13 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
value = (tree) n->value;
if (TREE_CODE (value) == INDIRECT_REF)
{
/* Assume that the argument types properly match the
parameter types. We can't compare them well enough
without a comptypes langhook, and we don't want to
call convert and introduce a NOP_EXPR to convert
between two equivalent types (i.e. that only differ
in use of typedef names). */
if (!lang_hooks.types_compatible_p
(TREE_TYPE (*tp), TREE_TYPE (TREE_OPERAND (value, 0))))
*tp = fold_convert (TREE_TYPE (*tp),
TREE_OPERAND (value, 0));
else
*tp = TREE_OPERAND (value, 0);
return copy_body_r (tp, walk_subtrees, data);
}
}
......@@ -626,7 +617,9 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
{
value = (tree) n->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);
return copy_body_r (tp, walk_subtrees, data);
......@@ -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));
TREE_TYPE (var) = remap_type (TREE_TYPE (var), id);
/* 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
......@@ -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
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)))
if (variably_modified_type_p (TREE_TYPE (t), NULL))
{
inline_forbidden_reason
= N_("%Jfunction '%F' can never be inlined "
......
......@@ -2352,16 +2352,20 @@ do { tree _node = (NODE); \
}
/* 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
decl is static. (Taking the address of a volatile variable is not
volatile.) If it's a constant, the address is both invariant and
constant. Otherwise it's neither. */
it. If it's a decl, it's invariant and constant if the decl is static.
It's also invariant if it's a decl in the current function. (Taking the
address of a volatile variable is not volatile.) If it's a constant,
the address is both invariant and constant. Otherwise it's neither. */
if (TREE_CODE (node) == INDIRECT_REF)
UPDATE_TITCSE (node);
else if (DECL_P (node))
{
if (!staticp (node))
if (staticp (node))
;
else if (decl_function_context (node) == current_function_decl)
tc = false;
else
ti = tc = false;
}
else if (TREE_CODE_CLASS (TREE_CODE (node)) == 'c')
;
......@@ -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
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:
size. If FN is nonzero, only return true if a modifier of the type
or position of FN is a variable or parameter inside FN.
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 (tree type)
variably_modified_type_p (tree type, tree fn)
{
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)
return false;
......@@ -4708,9 +4741,8 @@ variably_modified_type_p (tree type)
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. */
t = TYPE_SIZE (type);
if (t && t != error_mark_node && TREE_CODE (t) != INTEGER_CST)
return true;
RETURN_TRUE_IF_VAR (TYPE_SIZE (type));
RETURN_TRUE_IF_VAR (TYPE_SIZE_UNIT(type));
switch (TREE_CODE (type))
{
......@@ -4719,7 +4751,7 @@ variably_modified_type_p (tree type)
case ARRAY_TYPE:
case SET_TYPE:
case VECTOR_TYPE:
if (variably_modified_type_p (TREE_TYPE (type)))
if (variably_modified_type_p (TREE_TYPE (type), fn))
return true;
break;
......@@ -4727,13 +4759,13 @@ variably_modified_type_p (tree type)
case METHOD_TYPE:
/* If TYPE is a function type, it is variably modified if any of the
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;
for (t = TYPE_ARG_TYPES (type);
t && t != void_list_node;
t = TREE_CHAIN (t))
if (variably_modified_type_p (TREE_VALUE (t)))
if (variably_modified_type_p (TREE_VALUE (t), fn))
return true;
break;
......@@ -4744,13 +4776,8 @@ variably_modified_type_p (tree type)
case CHAR_TYPE:
/* Scalar types are variably modified if their end points
aren't constant. */
t = TYPE_MIN_VALUE (type);
if (t && t != error_mark_node && TREE_CODE (t) != INTEGER_CST)
return true;
t = TYPE_MAX_VALUE (type);
if (t && t != error_mark_node && TREE_CODE (t) != INTEGER_CST)
return true;
RETURN_TRUE_IF_VAR (TYPE_MIN_VALUE (type));
RETURN_TRUE_IF_VAR (TYPE_MAX_VALUE (type));
break;
case RECORD_TYPE:
......@@ -4763,14 +4790,12 @@ variably_modified_type_p (tree type)
for (t = TYPE_FIELDS (type); t; t = TREE_CHAIN (t))
if (TREE_CODE (t) == FIELD_DECL)
{
tree t1 = DECL_FIELD_OFFSET (t);
if (t1 && t1 != error_mark_node && TREE_CODE (t1) != INTEGER_CST)
return true;
RETURN_TRUE_IF_VAR (DECL_FIELD_OFFSET (t));
RETURN_TRUE_IF_VAR (DECL_SIZE (t));
RETURN_TRUE_IF_VAR (DECL_SIZE_UNIT (t));
t1 = DECL_SIZE (t);
if (t1 && t1 != error_mark_node && TREE_CODE (t1) != INTEGER_CST)
return true;
if (TREE_CODE (type) == QUAL_UNION_TYPE)
RETURN_TRUE_IF_VAR (DECL_QUALIFIER (t));
}
break;
......@@ -4780,7 +4805,9 @@ variably_modified_type_p (tree type)
/* 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);
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
......
......@@ -3469,7 +3469,7 @@ extern int objects_must_conflict_p (tree, tree);
/* In tree.c */
extern int really_constant_p (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_floor_log2 (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