#include "gimple-iterator.h"
#include "gimplify.h"
#include "tree-dfa.h"
-#include "params.h"
#include "langhooks-def.h"
#include "tree-diagnostic.h"
#include "except.h"
vec_free (BLOCK_NONLOCALIZED_VARS (node));
else if (code == TREE_BINFO)
vec_free (BINFO_BASE_ACCESSES (node));
+ else if (code == OPTIMIZATION_NODE)
+ cl_optimization_option_free (TREE_OPTIMIZATION (node));
+ else if (code == TARGET_OPTION_NODE)
+ cl_target_option_free (TREE_TARGET_OPTION (node));
ggc_free (node);
}
\f
if (TYPE_SIGN (type) == UNSIGNED)
{
/* Cache [0, N). */
- limit = INTEGER_SHARE_LIMIT;
- if (IN_RANGE (hwi, 0, INTEGER_SHARE_LIMIT - 1))
+ limit = param_integer_share_limit;
+ if (IN_RANGE (hwi, 0, param_integer_share_limit - 1))
ix = hwi;
}
else
{
/* Cache [-1, N). */
- limit = INTEGER_SHARE_LIMIT + 1;
- if (IN_RANGE (hwi, -1, INTEGER_SHARE_LIMIT - 1))
+ limit = param_integer_share_limit + 1;
+ if (IN_RANGE (hwi, -1, param_integer_share_limit - 1))
ix = hwi + 1;
}
break;
if (TYPE_UNSIGNED (type))
{
/* Cache 0..N */
- limit = INTEGER_SHARE_LIMIT;
+ limit = param_integer_share_limit;
/* This is a little hokie, but if the prec is smaller than
- what is necessary to hold INTEGER_SHARE_LIMIT, then the
+ what is necessary to hold param_integer_share_limit, then the
obvious test will not get the correct answer. */
if (prec < HOST_BITS_PER_WIDE_INT)
{
- if (tree_to_uhwi (t) < (unsigned HOST_WIDE_INT) INTEGER_SHARE_LIMIT)
+ if (tree_to_uhwi (t)
+ < (unsigned HOST_WIDE_INT) param_integer_share_limit)
ix = tree_to_uhwi (t);
}
- else if (wi::ltu_p (wi::to_wide (t), INTEGER_SHARE_LIMIT))
+ else if (wi::ltu_p (wi::to_wide (t), param_integer_share_limit))
ix = tree_to_uhwi (t);
}
else
{
/* Cache -1..N */
- limit = INTEGER_SHARE_LIMIT + 1;
+ limit = param_integer_share_limit + 1;
if (integer_minus_onep (t))
ix = 0;
{
if (prec < HOST_BITS_PER_WIDE_INT)
{
- if (tree_to_shwi (t) < INTEGER_SHARE_LIMIT)
+ if (tree_to_shwi (t) < param_integer_share_limit)
ix = tree_to_shwi (t) + 1;
}
- else if (wi::ltu_p (wi::to_wide (t), INTEGER_SHARE_LIMIT))
+ else if (wi::ltu_p (wi::to_wide (t), param_integer_share_limit))
ix = tree_to_shwi (t) + 1;
}
}
tree
build_vector_from_ctor (tree type, vec<constructor_elt, va_gc> *v)
{
+ if (vec_safe_length (v) == 0)
+ return build_zero_cst (type);
+
unsigned HOST_WIDE_INT idx, nelts;
tree value;
return t;
}
+/* Returns the last FIELD_DECL in the TYPE_FIELDS of the RECORD_TYPE or
+ UNION_TYPE TYPE, or NULL_TREE if none. */
+
+tree
+last_field (const_tree type)
+{
+ tree last = NULL_TREE;
+
+ for (tree fld = TYPE_FIELDS (type); fld; fld = TREE_CHAIN (fld))
+ {
+ if (TREE_CODE (fld) != FIELD_DECL)
+ continue;
+
+ last = fld;
+ }
+
+ return last;
+}
+
/* Concatenate two chains of nodes (chained through TREE_CHAIN)
by modifying the last node in chain 1 to point to chain 2.
This is the Lisp primitive `nconc'. */
TYPE_TYPELESS_STORAGE (copy) = 0;
TYPE_FIELDS (copy) = NULL;
TYPE_BINFO (copy) = NULL;
+ TYPE_FINAL_P (copy) = 0;
+ TYPE_EMPTY_P (copy) = 0;
}
else
- TYPE_VALUES (copy) = NULL;
+ {
+ TYPE_VALUES (copy) = NULL;
+ ENUM_IS_OPAQUE (copy) = 0;
+ ENUM_IS_SCOPED (copy) = 0;
+ }
/* Build copy of TYPE_DECL in TYPE_NAME if necessary.
This is needed for ODR violation warnings to come out right (we
BINFO_INHERITANCE_CHAIN (binfo) = NULL_TREE;
BINFO_SUBVTT_INDEX (binfo) = NULL_TREE;
BINFO_VPTR_FIELD (binfo) = NULL_TREE;
+ TREE_PUBLIC (binfo) = 0;
FOR_EACH_VEC_ELT (*BINFO_BASE_BINFOS (binfo), i, t)
free_lang_data_in_binfo (t);
{
if (TREE_CODE (type) == ENUMERAL_TYPE)
{
+ ENUM_IS_OPAQUE (type) = 0;
+ ENUM_IS_SCOPED (type) = 0;
/* Type values are used only for C++ ODR checking. Drop them
for all type variants and non-ODR types.
For ODR types the data is freed in free_odr_warning_data. */
while (*nextp)
{
tree var = *nextp;
- if (fndecl_built_in_p (var))
+ if (TREE_CODE (var) == FUNCTION_DECL
+ && fndecl_built_in_p (var))
*nextp = TREE_CHAIN (var);
else
nextp = &TREE_CHAIN (var);
}
}
-namespace inchash
-{
-
-/* Generate a hash value for an expression. This can be used iteratively
- by passing a previous result as the HSTATE argument.
-
- This function is intended to produce the same hash for expressions which
- would compare equal using operand_equal_p. */
-void
-add_expr (const_tree t, inchash::hash &hstate, unsigned int flags)
-{
- int i;
- enum tree_code code;
- enum tree_code_class tclass;
-
- if (t == NULL_TREE || t == error_mark_node)
- {
- hstate.merge_hash (0);
- return;
- }
-
- STRIP_ANY_LOCATION_WRAPPER (t);
-
- if (!(flags & OEP_ADDRESS_OF))
- STRIP_NOPS (t);
-
- code = TREE_CODE (t);
-
- switch (code)
- {
- /* Alas, constants aren't shared, so we can't rely on pointer
- identity. */
- case VOID_CST:
- hstate.merge_hash (0);
- return;
- case INTEGER_CST:
- gcc_checking_assert (!(flags & OEP_ADDRESS_OF));
- for (i = 0; i < TREE_INT_CST_EXT_NUNITS (t); i++)
- hstate.add_hwi (TREE_INT_CST_ELT (t, i));
- return;
- case REAL_CST:
- {
- unsigned int val2;
- if (!HONOR_SIGNED_ZEROS (t) && real_zerop (t))
- val2 = rvc_zero;
- else
- val2 = real_hash (TREE_REAL_CST_PTR (t));
- hstate.merge_hash (val2);
- return;
- }
- case FIXED_CST:
- {
- unsigned int val2 = fixed_hash (TREE_FIXED_CST_PTR (t));
- hstate.merge_hash (val2);
- return;
- }
- case STRING_CST:
- hstate.add ((const void *) TREE_STRING_POINTER (t),
- TREE_STRING_LENGTH (t));
- return;
- case COMPLEX_CST:
- inchash::add_expr (TREE_REALPART (t), hstate, flags);
- inchash::add_expr (TREE_IMAGPART (t), hstate, flags);
- return;
- case VECTOR_CST:
- {
- hstate.add_int (VECTOR_CST_NPATTERNS (t));
- hstate.add_int (VECTOR_CST_NELTS_PER_PATTERN (t));
- unsigned int count = vector_cst_encoded_nelts (t);
- for (unsigned int i = 0; i < count; ++i)
- inchash::add_expr (VECTOR_CST_ENCODED_ELT (t, i), hstate, flags);
- return;
- }
- case SSA_NAME:
- /* We can just compare by pointer. */
- hstate.add_hwi (SSA_NAME_VERSION (t));
- return;
- case PLACEHOLDER_EXPR:
- /* The node itself doesn't matter. */
- return;
- case BLOCK:
- case OMP_CLAUSE:
- /* Ignore. */
- return;
- case TREE_LIST:
- /* A list of expressions, for a CALL_EXPR or as the elements of a
- VECTOR_CST. */
- for (; t; t = TREE_CHAIN (t))
- inchash::add_expr (TREE_VALUE (t), hstate, flags);
- return;
- case CONSTRUCTOR:
- {
- unsigned HOST_WIDE_INT idx;
- tree field, value;
- flags &= ~OEP_ADDRESS_OF;
- FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t), idx, field, value)
- {
- inchash::add_expr (field, hstate, flags);
- inchash::add_expr (value, hstate, flags);
- }
- return;
- }
- case STATEMENT_LIST:
- {
- tree_stmt_iterator i;
- for (i = tsi_start (CONST_CAST_TREE (t));
- !tsi_end_p (i); tsi_next (&i))
- inchash::add_expr (tsi_stmt (i), hstate, flags);
- return;
- }
- case TREE_VEC:
- for (i = 0; i < TREE_VEC_LENGTH (t); ++i)
- inchash::add_expr (TREE_VEC_ELT (t, i), hstate, flags);
- return;
- case IDENTIFIER_NODE:
- hstate.add_object (IDENTIFIER_HASH_VALUE (t));
- return;
- case FUNCTION_DECL:
- /* When referring to a built-in FUNCTION_DECL, use the __builtin__ form.
- Otherwise nodes that compare equal according to operand_equal_p might
- get different hash codes. However, don't do this for machine specific
- or front end builtins, since the function code is overloaded in those
- cases. */
- if (DECL_BUILT_IN_CLASS (t) == BUILT_IN_NORMAL
- && builtin_decl_explicit_p (DECL_FUNCTION_CODE (t)))
- {
- t = builtin_decl_explicit (DECL_FUNCTION_CODE (t));
- code = TREE_CODE (t);
- }
- /* FALL THROUGH */
- default:
- if (POLY_INT_CST_P (t))
- {
- for (unsigned int i = 0; i < NUM_POLY_INT_COEFFS; ++i)
- hstate.add_wide_int (wi::to_wide (POLY_INT_CST_COEFF (t, i)));
- return;
- }
- tclass = TREE_CODE_CLASS (code);
-
- if (tclass == tcc_declaration)
- {
- /* DECL's have a unique ID */
- hstate.add_hwi (DECL_UID (t));
- }
- else if (tclass == tcc_comparison && !commutative_tree_code (code))
- {
- /* For comparisons that can be swapped, use the lower
- tree code. */
- enum tree_code ccode = swap_tree_comparison (code);
- if (code < ccode)
- ccode = code;
- hstate.add_object (ccode);
- inchash::add_expr (TREE_OPERAND (t, ccode != code), hstate, flags);
- inchash::add_expr (TREE_OPERAND (t, ccode == code), hstate, flags);
- }
- else if (CONVERT_EXPR_CODE_P (code))
- {
- /* NOP_EXPR and CONVERT_EXPR are considered equal by
- operand_equal_p. */
- enum tree_code ccode = NOP_EXPR;
- hstate.add_object (ccode);
-
- /* Don't hash the type, that can lead to having nodes which
- compare equal according to operand_equal_p, but which
- have different hash codes. Make sure to include signedness
- in the hash computation. */
- hstate.add_int (TYPE_UNSIGNED (TREE_TYPE (t)));
- inchash::add_expr (TREE_OPERAND (t, 0), hstate, flags);
- }
- /* For OEP_ADDRESS_OF, hash MEM_EXPR[&decl, 0] the same as decl. */
- else if (code == MEM_REF
- && (flags & OEP_ADDRESS_OF) != 0
- && TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR
- && DECL_P (TREE_OPERAND (TREE_OPERAND (t, 0), 0))
- && integer_zerop (TREE_OPERAND (t, 1)))
- inchash::add_expr (TREE_OPERAND (TREE_OPERAND (t, 0), 0),
- hstate, flags);
- /* Don't ICE on FE specific trees, or their arguments etc.
- during operand_equal_p hash verification. */
- else if (!IS_EXPR_CODE_CLASS (tclass))
- gcc_assert (flags & OEP_HASH_CHECK);
- else
- {
- unsigned int sflags = flags;
-
- hstate.add_object (code);
-
- switch (code)
- {
- case ADDR_EXPR:
- gcc_checking_assert (!(flags & OEP_ADDRESS_OF));
- flags |= OEP_ADDRESS_OF;
- sflags = flags;
- break;
-
- case INDIRECT_REF:
- case MEM_REF:
- case TARGET_MEM_REF:
- flags &= ~OEP_ADDRESS_OF;
- sflags = flags;
- break;
-
- case ARRAY_REF:
- case ARRAY_RANGE_REF:
- case COMPONENT_REF:
- case BIT_FIELD_REF:
- sflags &= ~OEP_ADDRESS_OF;
- break;
-
- case COND_EXPR:
- flags &= ~OEP_ADDRESS_OF;
- break;
-
- case WIDEN_MULT_PLUS_EXPR:
- case WIDEN_MULT_MINUS_EXPR:
- {
- /* The multiplication operands are commutative. */
- inchash::hash one, two;
- inchash::add_expr (TREE_OPERAND (t, 0), one, flags);
- inchash::add_expr (TREE_OPERAND (t, 1), two, flags);
- hstate.add_commutative (one, two);
- inchash::add_expr (TREE_OPERAND (t, 2), two, flags);
- return;
- }
-
- case CALL_EXPR:
- if (CALL_EXPR_FN (t) == NULL_TREE)
- hstate.add_int (CALL_EXPR_IFN (t));
- break;
-
- case TARGET_EXPR:
- /* For TARGET_EXPR, just hash on the TARGET_EXPR_SLOT.
- Usually different TARGET_EXPRs just should use
- different temporaries in their slots. */
- inchash::add_expr (TARGET_EXPR_SLOT (t), hstate, flags);
- return;
-
- default:
- break;
- }
-
- /* Don't hash the type, that can lead to having nodes which
- compare equal according to operand_equal_p, but which
- have different hash codes. */
- if (code == NON_LVALUE_EXPR)
- {
- /* Make sure to include signness in the hash computation. */
- hstate.add_int (TYPE_UNSIGNED (TREE_TYPE (t)));
- inchash::add_expr (TREE_OPERAND (t, 0), hstate, flags);
- }
-
- else if (commutative_tree_code (code))
- {
- /* It's a commutative expression. We want to hash it the same
- however it appears. We do this by first hashing both operands
- and then rehashing based on the order of their independent
- hashes. */
- inchash::hash one, two;
- inchash::add_expr (TREE_OPERAND (t, 0), one, flags);
- inchash::add_expr (TREE_OPERAND (t, 1), two, flags);
- hstate.add_commutative (one, two);
- }
- else
- for (i = TREE_OPERAND_LENGTH (t) - 1; i >= 0; --i)
- inchash::add_expr (TREE_OPERAND (t, i), hstate,
- i == 0 ? flags : sflags);
- }
- return;
- }
-}
-
-}
-
/* Constructors for pointer, array and function types.
(RECORD_TYPE, UNION_TYPE and ENUMERAL_TYPE nodes are
constructed by language-dependent code, not here.) */
uint64_type_node = make_or_reuse_type (64, 1);
/* Decimal float types. */
- dfloat32_type_node = make_node (REAL_TYPE);
- TYPE_PRECISION (dfloat32_type_node) = DECIMAL32_TYPE_SIZE;
- SET_TYPE_MODE (dfloat32_type_node, SDmode);
- layout_type (dfloat32_type_node);
- dfloat32_ptr_type_node = build_pointer_type (dfloat32_type_node);
-
- dfloat64_type_node = make_node (REAL_TYPE);
- TYPE_PRECISION (dfloat64_type_node) = DECIMAL64_TYPE_SIZE;
- SET_TYPE_MODE (dfloat64_type_node, DDmode);
- layout_type (dfloat64_type_node);
- dfloat64_ptr_type_node = build_pointer_type (dfloat64_type_node);
-
- dfloat128_type_node = make_node (REAL_TYPE);
- TYPE_PRECISION (dfloat128_type_node) = DECIMAL128_TYPE_SIZE;
- SET_TYPE_MODE (dfloat128_type_node, TDmode);
- layout_type (dfloat128_type_node);
- dfloat128_ptr_type_node = build_pointer_type (dfloat128_type_node);
+ if (targetm.decimal_float_supported_p ())
+ {
+ dfloat32_type_node = make_node (REAL_TYPE);
+ TYPE_PRECISION (dfloat32_type_node) = DECIMAL32_TYPE_SIZE;
+ SET_TYPE_MODE (dfloat32_type_node, SDmode);
+ layout_type (dfloat32_type_node);
+
+ dfloat64_type_node = make_node (REAL_TYPE);
+ TYPE_PRECISION (dfloat64_type_node) = DECIMAL64_TYPE_SIZE;
+ SET_TYPE_MODE (dfloat64_type_node, DDmode);
+ layout_type (dfloat64_type_node);
+
+ dfloat128_type_node = make_node (REAL_TYPE);
+ TYPE_PRECISION (dfloat128_type_node) = DECIMAL128_TYPE_SIZE;
+ SET_TYPE_MODE (dfloat128_type_node, TDmode);
+ layout_type (dfloat128_type_node);
+ }
complex_integer_type_node = build_complex_type (integer_type_node, true);
complex_float_type_node = build_complex_type (float_type_node, true);
return make_vector_type (innertype, nunits, VOIDmode);
}
-/* Build truth vector with specified length and number of units. */
+/* Build a truth vector with NUNITS units, giving it mode MASK_MODE. */
tree
-build_truth_vector_type (poly_uint64 nunits, poly_uint64 vector_size)
+build_truth_vector_type_for_mode (poly_uint64 nunits, machine_mode mask_mode)
{
- machine_mode mask_mode
- = targetm.vectorize.get_mask_mode (nunits, vector_size).else_blk ();
-
- poly_uint64 vsize;
- if (mask_mode == BLKmode)
- vsize = vector_size * BITS_PER_UNIT;
- else
- vsize = GET_MODE_BITSIZE (mask_mode);
+ gcc_assert (mask_mode != BLKmode);
+ poly_uint64 vsize = GET_MODE_BITSIZE (mask_mode);
unsigned HOST_WIDE_INT esize = vector_element_size (vsize, nunits);
-
tree bool_type = build_nonstandard_boolean_type (esize);
return make_vector_type (bool_type, nunits, mask_mode);
}
-/* Returns a vector type corresponding to a comparison of VECTYPE. */
+/* Build a vector type that holds one boolean result for each element of
+ vector type VECTYPE. The public interface for this operation is
+ truth_type_for. */
-tree
-build_same_sized_truth_vector_type (tree vectype)
+static tree
+build_truth_vector_type_for (tree vectype)
{
- if (VECTOR_BOOLEAN_TYPE_P (vectype))
- return vectype;
+ machine_mode vector_mode = TYPE_MODE (vectype);
+ poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
- poly_uint64 size = GET_MODE_SIZE (TYPE_MODE (vectype));
+ machine_mode mask_mode;
+ if (VECTOR_MODE_P (vector_mode)
+ && targetm.vectorize.get_mask_mode (vector_mode).exists (&mask_mode))
+ return build_truth_vector_type_for_mode (nunits, mask_mode);
- if (known_eq (size, 0U))
- size = tree_to_uhwi (TYPE_SIZE_UNIT (vectype));
+ poly_uint64 vsize = tree_to_poly_uint64 (TYPE_SIZE (vectype));
+ unsigned HOST_WIDE_INT esize = vector_element_size (vsize, nunits);
+ tree bool_type = build_nonstandard_boolean_type (esize);
- return build_truth_vector_type (TYPE_VECTOR_SUBPARTS (vectype), size);
+ return make_vector_type (bool_type, nunits, BLKmode);
}
-/* Similarly, but builds a variant type with TYPE_VECTOR_OPAQUE set. */
+/* Like build_vector_type, but builds a variant type with TYPE_VECTOR_OPAQUE
+ set. */
tree
build_opaque_vector_type (tree innertype, poly_int64 nunits)
}
}
-/* Given an initializer INIT for a TYPE, return true if INIT is zero
- so that it can be replaced by value initialization. This function
- distinguishes betwen empty strings as initializers for arrays and
- for pointers (which make it return false). */
-
-bool
-type_initializer_zero_p (tree type, tree init)
-{
- if (type == error_mark_node || init == error_mark_node)
- return false;
-
- STRIP_NOPS (init);
-
- if (POINTER_TYPE_P (type))
- return TREE_CODE (init) != STRING_CST && initializer_zerop (init);
-
- if (TREE_CODE (init) != CONSTRUCTOR)
- return initializer_zerop (init);
-
- if (TREE_CODE (type) == ARRAY_TYPE)
- {
- tree elt_type = TREE_TYPE (type);
- elt_type = TYPE_MAIN_VARIANT (elt_type);
- if (elt_type == char_type_node)
- return initializer_zerop (init);
-
- tree elt_init;
- unsigned HOST_WIDE_INT i;
- FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (init), i, elt_init)
- if (!type_initializer_zero_p (elt_type, elt_init))
- return false;
- return true;
- }
-
- if (TREE_CODE (type) != RECORD_TYPE)
- return initializer_zerop (init);
-
- tree fld = TYPE_FIELDS (type);
-
- tree fld_init;
- unsigned HOST_WIDE_INT i;
- FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (init), i, fld_init)
- {
- /* Advance to the next member, skipping over everything that
- canot be initialized (including unnamed bit-fields). */
- while (TREE_CODE (fld) != FIELD_DECL
- || DECL_ARTIFICIAL (fld)
- || (DECL_BIT_FIELD (fld) && !DECL_NAME (fld)))
- {
- fld = DECL_CHAIN (fld);
- if (!fld)
- return true;
- continue;
- }
-
- tree fldtype = TREE_TYPE (fld);
- if (!type_initializer_zero_p (fldtype, fld_init))
- return false;
-
- fld = DECL_CHAIN (fld);
- if (!fld)
- break;
- }
-
- return true;
-}
-
/* Check if vector VEC consists of all the equal elements and
that the number of elements corresponds to the type of VEC.
The function returns first element of the vector
{
if (VECTOR_BOOLEAN_TYPE_P (type))
return type;
- return build_truth_vector_type (TYPE_VECTOR_SUBPARTS (type),
- GET_MODE_SIZE (TYPE_MODE (type)));
+ return build_truth_vector_type_for (type);
}
else
return boolean_type_node;
return NULL_TREE;
}
-/* Returns true if REF is an array reference or a component reference
- to an array at the end of a structure.
+/* Returns true if REF is an array reference, component reference,
+ or memory reference to an array at the end of a structure.
If this is the case, the array may be allocated larger
than its upper bound implies. */
else if (TREE_CODE (ref) == COMPONENT_REF
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (ref, 1))) == ARRAY_TYPE)
atype = TREE_TYPE (TREE_OPERAND (ref, 1));
+ else if (TREE_CODE (ref) == MEM_REF)
+ {
+ tree arg = TREE_OPERAND (ref, 0);
+ if (TREE_CODE (arg) == ADDR_EXPR)
+ arg = TREE_OPERAND (arg, 0);
+ tree argtype = TREE_TYPE (arg);
+ if (TREE_CODE (argtype) == RECORD_TYPE)
+ {
+ if (tree fld = last_field (argtype))
+ {
+ atype = TREE_TYPE (fld);
+ if (TREE_CODE (atype) != ARRAY_TYPE)
+ return false;
+ if (VAR_P (arg) && DECL_SIZE (fld))
+ return false;
+ }
+ else
+ return false;
+ }
+ else
+ return false;
+ }
else
return false;
return SUBSTITUTE_PLACEHOLDER_IN_EXPR (DECL_FIELD_OFFSET (field), exp);
}
+/* Given the initializer INIT, return the initializer for the field
+ DECL if it exists, otherwise null. Used to obtain the initializer
+ for a flexible array member and determine its size. */
+
+static tree
+get_initializer_for (tree init, tree decl)
+{
+ STRIP_NOPS (init);
+
+ tree fld, fld_init;
+ unsigned HOST_WIDE_INT i;
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), i, fld, fld_init)
+ {
+ if (decl == fld)
+ return fld_init;
+
+ if (TREE_CODE (fld) == CONSTRUCTOR)
+ {
+ fld_init = get_initializer_for (fld_init, decl);
+ if (fld_init)
+ return fld_init;
+ }
+ }
+
+ return NULL_TREE;
+}
+
/* Determines the size of the member referenced by the COMPONENT_REF
REF, using its initializer expression if necessary in order to
determine the size of an initialized flexible array member.
+ If non-null, *INTERIOR_ZERO_LENGTH is set when REF refers to
+ an interior zero-length array.
Returns the size (which might be zero for an object with
an uninitialized flexible array member) or null if the size
cannot be determined. */
tree
-component_ref_size (tree ref)
+component_ref_size (tree ref, bool *interior_zero_length /* = NULL */)
{
gcc_assert (TREE_CODE (ref) == COMPONENT_REF);
+ bool int_0_len = false;
+ if (!interior_zero_length)
+ interior_zero_length = &int_0_len;
+
tree member = TREE_OPERAND (ref, 1);
- /* If the member is not an array, or is not last, or is an array with
- more than one element, return its size. Otherwise it's either
- a bona fide flexible array member, or a zero-length array member,
- or an array of length one treated as such. */
- tree size = DECL_SIZE_UNIT (member);
- if (size)
+ tree memsize = DECL_SIZE_UNIT (member);
+ if (memsize)
{
tree memtype = TREE_TYPE (member);
- if (TREE_CODE (memtype) != ARRAY_TYPE
- || !array_at_struct_end_p (ref))
- return size;
+ if (TREE_CODE (memtype) != ARRAY_TYPE)
+ return memsize;
+
+ bool trailing = array_at_struct_end_p (ref);
+ bool zero_length = integer_zerop (memsize);
+ if (!trailing && (!interior_zero_length || !zero_length))
+ /* MEMBER is either an interior array or is an array with
+ more than one element. */
+ return memsize;
- if (!integer_zerop (size))
+ *interior_zero_length = zero_length && !trailing;
+ if (*interior_zero_length)
+ memsize = NULL_TREE;
+
+ if (!zero_length)
if (tree dom = TYPE_DOMAIN (memtype))
if (tree min = TYPE_MIN_VALUE (dom))
if (tree max = TYPE_MAX_VALUE (dom))
{
offset_int minidx = wi::to_offset (min);
offset_int maxidx = wi::to_offset (max);
- if (maxidx - minidx > 1)
- return size;
+ if (maxidx - minidx > 0)
+ /* MEMBER is an array with more than 1 element. */
+ return memsize;
}
}
+ /* MEMBER is either a bona fide flexible array member, or a zero-length
+ array member, or an array of length one treated as such. */
+
/* If the reference is to a declared object and the member a true
flexible array, try to determine its size from its initializer. */
- poly_int64 off = 0;
- tree base = get_addr_base_and_unit_offset (ref, &off);
+ poly_int64 baseoff = 0;
+ tree base = get_addr_base_and_unit_offset (ref, &baseoff);
if (!base || !VAR_P (base))
- return NULL_TREE;
+ {
+ if (!*interior_zero_length)
+ return NULL_TREE;
- /* The size of any member of a declared object other than a flexible
- array member is that obtained above. */
- if (size)
- return size;
+ if (TREE_CODE (TREE_OPERAND (ref, 0)) != COMPONENT_REF)
+ return NULL_TREE;
- if (tree init = DECL_INITIAL (base))
- if (TREE_CODE (init) == CONSTRUCTOR)
+ base = TREE_OPERAND (ref, 0);
+ while (TREE_CODE (base) == COMPONENT_REF)
+ base = TREE_OPERAND (base, 0);
+ baseoff = tree_to_poly_int64 (byte_position (TREE_OPERAND (ref, 1)));
+ }
+
+ /* BASE is the declared object of which MEMBER is either a member
+ or that is is cast to REFTYPE (e.g., a char buffer used to store
+ a REFTYPE object). */
+ tree reftype = TREE_TYPE (TREE_OPERAND (ref, 0));
+ tree basetype = TREE_TYPE (base);
+
+ /* Determine the base type of the referenced object. If it's
+ the same as REFTYPE and MEMBER has a known size, return it. */
+ tree bt = basetype;
+ if (!*interior_zero_length)
+ while (TREE_CODE (bt) == ARRAY_TYPE)
+ bt = TREE_TYPE (bt);
+ bool typematch = useless_type_conversion_p (reftype, bt);
+ if (memsize && typematch)
+ return memsize;
+
+ memsize = NULL_TREE;
+
+ if (typematch)
+ /* MEMBER is a true flexible array member. Compute its size from
+ the initializer of the BASE object if it has one. */
+ if (tree init = DECL_P (base) ? DECL_INITIAL (base) : NULL_TREE)
{
- off <<= LOG2_BITS_PER_UNIT;
- init = fold_ctor_reference (NULL_TREE, init, off, 0, base);
+ init = get_initializer_for (init, member);
if (init)
- return TYPE_SIZE_UNIT (TREE_TYPE (init));
+ {
+ memsize = TYPE_SIZE_UNIT (TREE_TYPE (init));
+ if (tree refsize = TYPE_SIZE_UNIT (reftype))
+ {
+ /* Use the larger of the initializer size and the tail
+ padding in the enclosing struct. */
+ poly_int64 rsz = tree_to_poly_int64 (refsize);
+ rsz -= baseoff;
+ if (known_lt (tree_to_poly_int64 (memsize), rsz))
+ memsize = wide_int_to_tree (TREE_TYPE (memsize), rsz);
+ }
+
+ baseoff = 0;
+ }
}
+ if (!memsize)
+ {
+ if (typematch)
+ {
+ if (DECL_P (base)
+ && DECL_EXTERNAL (base)
+ && bt == basetype
+ && !*interior_zero_length)
+ /* The size of a flexible array member of an extern struct
+ with no initializer cannot be determined (it's defined
+ in another translation unit and can have an initializer
+ with an arbitrary number of elements). */
+ return NULL_TREE;
+
+ /* Use the size of the base struct or, for interior zero-length
+ arrays, the size of the enclosing type. */
+ memsize = TYPE_SIZE_UNIT (bt);
+ }
+ else if (DECL_P (base))
+ /* Use the size of the BASE object (possibly an array of some
+ other type such as char used to store the struct). */
+ memsize = DECL_SIZE_UNIT (base);
+ else
+ return NULL_TREE;
+ }
+
+ /* If the flexible array member has a known size use the greater
+ of it and the tail padding in the enclosing struct.
+ Otherwise, when the size of the flexible array member is unknown
+ and the referenced object is not a struct, use the size of its
+ type when known. This detects sizes of array buffers when cast
+ to struct types with flexible array members. */
+ if (memsize)
+ {
+ poly_int64 memsz64 = memsize ? tree_to_poly_int64 (memsize) : 0;
+ if (known_lt (baseoff, memsz64))
+ {
+ memsz64 -= baseoff;
+ return wide_int_to_tree (TREE_TYPE (memsize), memsz64);
+ }
+ return integer_zero_node;
+ }
+
/* Return "don't know" for an external non-array object since its
flexible array member can be initialized to have any number of
elements. Otherwise, return zero because the flexible array
member has no elements. */
- return (DECL_EXTERNAL (base) && TREE_CODE (TREE_TYPE (base)) != ARRAY_TYPE
+ return (DECL_P (base)
+ && DECL_EXTERNAL (base)
+ && (!typematch
+ || TREE_CODE (basetype) != ARRAY_TYPE)
? NULL_TREE : integer_zero_node);
}
return default_is_empty_type (TYPE_MAIN_VARIANT (type));
}
+/* Determine whether TYPE is a structure with a flexible array member,
+ or a union containing such a structure (possibly recursively). */
+
+bool
+flexible_array_type_p (const_tree type)
+{
+ tree x, last;
+ switch (TREE_CODE (type))
+ {
+ case RECORD_TYPE:
+ last = NULL_TREE;
+ for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x))
+ if (TREE_CODE (x) == FIELD_DECL)
+ last = x;
+ if (last == NULL_TREE)
+ return false;
+ if (TREE_CODE (TREE_TYPE (last)) == ARRAY_TYPE
+ && TYPE_SIZE (TREE_TYPE (last)) == NULL_TREE
+ && TYPE_DOMAIN (TREE_TYPE (last)) != NULL_TREE
+ && TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (last))) == NULL_TREE)
+ return true;
+ return false;
+ case UNION_TYPE:
+ for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x))
+ {
+ if (TREE_CODE (x) == FIELD_DECL
+ && flexible_array_type_p (TREE_TYPE (x)))
+ return true;
+ }
+ return false;
+ default:
+ return false;
+ }
+}
+
/* Like int_size_in_bytes, but handle empty records specially. */
HOST_WIDE_INT
return TYPE_MAX_VALUE (ptrdiff_type_node);
}
+/* A wrapper around TARGET_VERIFY_TYPE_CONTEXT that makes the silent_p
+ parameter default to false and that weeds out error_mark_node. */
+
+bool
+verify_type_context (location_t loc, type_context_kind context,
+ const_tree type, bool silent_p)
+{
+ if (type == error_mark_node)
+ return true;
+
+ gcc_assert (TYPE_P (type));
+ return (!targetm.verify_type_context
+ || targetm.verify_type_context (loc, context, type, silent_p));
+}
+
#if CHECKING_P
namespace selftest {