- var = TREE_OPERAND (ptr, 0);
-
- while (var != pt_var
- && TREE_CODE (var) != BIT_FIELD_REF
- && TREE_CODE (var) != COMPONENT_REF
- && TREE_CODE (var) != ARRAY_REF
- && TREE_CODE (var) != ARRAY_RANGE_REF
- && TREE_CODE (var) != REALPART_EXPR
- && TREE_CODE (var) != IMAGPART_EXPR)
- var = TREE_OPERAND (var, 0);
- if (var != pt_var && TREE_CODE (var) == ARRAY_REF)
- var = TREE_OPERAND (var, 0);
- if (! TYPE_SIZE_UNIT (TREE_TYPE (var))
- || ! host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (var)), 1)
- || tree_int_cst_lt (TYPE_SIZE_UNIT (TREE_TYPE (pt_var)),
- TYPE_SIZE_UNIT (TREE_TYPE (var))))
+ tree v = var;
+ /* For &X->fld, compute object size only if fld isn't the last
+ field, as struct { int i; char c[1]; } is often used instead
+ of flexible array member. */
+ while (v && v != pt_var)
+ switch (TREE_CODE (v))
+ {
+ case ARRAY_REF:
+ if (TYPE_SIZE_UNIT (TREE_TYPE (TREE_OPERAND (v, 0)))
+ && TREE_CODE (TREE_OPERAND (v, 1)) == INTEGER_CST)
+ {
+ tree domain
+ = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (v, 0)));
+ if (domain
+ && TYPE_MAX_VALUE (domain)
+ && TREE_CODE (TYPE_MAX_VALUE (domain))
+ == INTEGER_CST
+ && tree_int_cst_lt (TREE_OPERAND (v, 1),
+ TYPE_MAX_VALUE (domain)))
+ {
+ v = NULL_TREE;
+ break;
+ }
+ }
+ v = TREE_OPERAND (v, 0);
+ break;
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
+ v = NULL_TREE;
+ break;
+ case COMPONENT_REF:
+ if (TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE)
+ {
+ v = NULL_TREE;
+ break;
+ }
+ while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
+ if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
+ != UNION_TYPE
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
+ != QUAL_UNION_TYPE)
+ break;
+ else
+ v = TREE_OPERAND (v, 0);
+ if (TREE_CODE (v) == COMPONENT_REF
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
+ == RECORD_TYPE)
+ {
+ tree fld_chain = TREE_CHAIN (TREE_OPERAND (v, 1));
+ for (; fld_chain; fld_chain = TREE_CHAIN (fld_chain))
+ if (TREE_CODE (fld_chain) == FIELD_DECL)
+ break;
+
+ if (fld_chain)
+ {
+ v = NULL_TREE;
+ break;
+ }
+ v = TREE_OPERAND (v, 0);
+ }
+ while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
+ if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
+ != UNION_TYPE
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
+ != QUAL_UNION_TYPE)
+ break;
+ else
+ v = TREE_OPERAND (v, 0);
+ if (v != pt_var)
+ v = NULL_TREE;
+ else
+ v = pt_var;
+ break;
+ default:
+ v = pt_var;
+ break;
+ }
+ if (v == pt_var)