* 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
+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.
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.
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 *);
}
/* 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;
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);
}
/* 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);
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;
}
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;
{
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))
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. */
return true;
}
\f
-/* 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)
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)
#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 \
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);
(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);
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)
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;
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
/* 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;
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). */
- *tp = TREE_OPERAND (value, 0);
+ 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);
}
}
{
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);
}
}
- /* 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
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 "
}
/* 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')
;
}
}
+/* 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;
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))
{
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;
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;
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:
for (t = TYPE_FIELDS (type); t; t = TREE_CHAIN (t))
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)
- return true;
-
- 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;
/* 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
/* 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);