#include "tree-pretty-print.h"
#include "selftest.h"
#include "langhooks.h"
+#include "options.h"
/* The pretty-printer code is primarily designed to closely follow
(GNU) C and C++ grammars. That is to be contrasted with spaghetti
pp_c_right_paren (pp);
}
+/* Try to fold *(type *)&op into op.fld.fld2[1] if possible.
+ Only used for printing expressions. Should punt if ambiguous
+ (e.g. in unions). */
+
+static tree
+c_fold_indirect_ref_for_warn (location_t loc, tree type, tree op,
+ offset_int &off)
+{
+ tree optype = TREE_TYPE (op);
+ if (off == 0)
+ {
+ if (lang_hooks.types_compatible_p (optype, type))
+ return op;
+ /* *(foo *)&complexfoo => __real__ complexfoo */
+ else if (TREE_CODE (optype) == COMPLEX_TYPE
+ && lang_hooks.types_compatible_p (type, TREE_TYPE (optype)))
+ return build1_loc (loc, REALPART_EXPR, type, op);
+ }
+ /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */
+ else if (TREE_CODE (optype) == COMPLEX_TYPE
+ && lang_hooks.types_compatible_p (type, TREE_TYPE (optype))
+ && tree_to_uhwi (TYPE_SIZE_UNIT (type)) == off)
+ {
+ off = 0;
+ return build1_loc (loc, IMAGPART_EXPR, type, op);
+ }
+ /* ((foo *)&fooarray)[x] => fooarray[x] */
+ if (TREE_CODE (optype) == ARRAY_TYPE
+ && TYPE_SIZE_UNIT (TREE_TYPE (optype))
+ && TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (optype))) == INTEGER_CST
+ && !integer_zerop (TYPE_SIZE_UNIT (TREE_TYPE (optype))))
+ {
+ tree type_domain = TYPE_DOMAIN (optype);
+ tree min_val = size_zero_node;
+ if (type_domain && TYPE_MIN_VALUE (type_domain))
+ min_val = TYPE_MIN_VALUE (type_domain);
+ offset_int el_sz = wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (optype)));
+ offset_int idx = off / el_sz;
+ offset_int rem = off % el_sz;
+ if (TREE_CODE (min_val) == INTEGER_CST)
+ {
+ tree index
+ = wide_int_to_tree (sizetype, idx + wi::to_offset (min_val));
+ op = build4_loc (loc, ARRAY_REF, TREE_TYPE (optype), op, index,
+ NULL_TREE, NULL_TREE);
+ off = rem;
+ if (tree ret = c_fold_indirect_ref_for_warn (loc, type, op, off))
+ return ret;
+ return op;
+ }
+ }
+ /* ((foo *)&struct_with_foo_field)[x] => COMPONENT_REF */
+ else if (TREE_CODE (optype) == RECORD_TYPE)
+ {
+ for (tree field = TYPE_FIELDS (optype);
+ field; field = DECL_CHAIN (field))
+ if (TREE_CODE (field) == FIELD_DECL
+ && TREE_TYPE (field) != error_mark_node
+ && TYPE_SIZE_UNIT (TREE_TYPE (field))
+ && TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (field))) == INTEGER_CST)
+ {
+ tree pos = byte_position (field);
+ if (TREE_CODE (pos) != INTEGER_CST)
+ continue;
+ offset_int upos = wi::to_offset (pos);
+ offset_int el_sz
+ = wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (field)));
+ if (upos <= off && off < upos + el_sz)
+ {
+ tree cop = build3_loc (loc, COMPONENT_REF, TREE_TYPE (field),
+ op, field, NULL_TREE);
+ off = off - upos;
+ if (tree ret = c_fold_indirect_ref_for_warn (loc, type, cop,
+ off))
+ return ret;
+ return cop;
+ }
+ }
+ }
+ /* Similarly for unions, but in this case try to be very conservative,
+ only match if some field has type compatible with type and it is the
+ only such field. */
+ else if (TREE_CODE (optype) == UNION_TYPE)
+ {
+ tree fld = NULL_TREE;
+ for (tree field = TYPE_FIELDS (optype);
+ field; field = DECL_CHAIN (field))
+ if (TREE_CODE (field) == FIELD_DECL
+ && TREE_TYPE (field) != error_mark_node
+ && lang_hooks.types_compatible_p (TREE_TYPE (field), type))
+ {
+ if (fld)
+ return NULL_TREE;
+ else
+ fld = field;
+ }
+ if (fld)
+ {
+ off = 0;
+ return build3_loc (loc, COMPONENT_REF, TREE_TYPE (fld), op, fld,
+ NULL_TREE);
+ }
+ }
+
+ return NULL_TREE;
+}
+
/* Print the MEM_REF expression REF, including its type and offset.
Apply casts as necessary if the type of the access is different
from the type of the accessed object. Produce compact output
offset_int elt_idx = 0;
/* True to include a cast to char* (for a nonzero final BYTE_OFF). */
bool char_cast = false;
- const bool addr = TREE_CODE (arg) == ADDR_EXPR;
- if (addr)
+ tree op = NULL_TREE;
+ bool array_ref_only = false;
+ if (TREE_CODE (arg) == ADDR_EXPR)
{
- arg = TREE_OPERAND (arg, 0);
- if (byte_off == 0)
+ op = c_fold_indirect_ref_for_warn (EXPR_LOCATION (e), TREE_TYPE (e),
+ TREE_OPERAND (arg, 0), byte_off);
+ /* Try to fold it back to component, array ref or their combination,
+ but print it only if the types and TBAA types are compatible. */
+ if (op
+ && byte_off == 0
+ && lang_hooks.types_compatible_p (TREE_TYPE (e), TREE_TYPE (op))
+ && (!flag_strict_aliasing
+ || (get_deref_alias_set (TREE_OPERAND (e, 1))
+ == get_alias_set (op))))
{
- pp->expression (arg);
+ pp->expression (op);
return;
}
+ if (op == NULL_TREE)
+ op = TREE_OPERAND (arg, 0);
+ /* If the types or TBAA types are incompatible, undo the
+ UNION_TYPE handling from c_fold_indirect_ref_for_warn, and similarly
+ undo __real__/__imag__ the code below doesn't try to handle. */
+ if (op != TREE_OPERAND (arg, 0)
+ && ((TREE_CODE (op) == COMPONENT_REF
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (op, 0))) == UNION_TYPE)
+ || TREE_CODE (op) == REALPART_EXPR
+ || TREE_CODE (op) == IMAGPART_EXPR))
+ op = TREE_OPERAND (op, 0);
+ if (op != TREE_OPERAND (arg, 0))
+ {
+ array_ref_only = true;
+ for (tree ref = op; ref != TREE_OPERAND (arg, 0);
+ ref = TREE_OPERAND (ref, 0))
+ if (TREE_CODE (ref) != ARRAY_REF)
+ {
+ array_ref_only = false;
+ break;
+ }
+ }
}
tree access_type = TREE_TYPE (e);
- if (TREE_CODE (access_type) == ARRAY_TYPE)
- access_type = TREE_TYPE (access_type);
- tree arg_type = TREE_TYPE (arg);
- if (POINTER_TYPE_P (arg_type))
- arg_type = TREE_TYPE (arg_type);
- if (TREE_CODE (arg_type) == ARRAY_TYPE)
- arg_type = TREE_TYPE (arg_type);
+ tree arg_type = TREE_TYPE (TREE_TYPE (arg));
if (tree access_size = TYPE_SIZE_UNIT (access_type))
- if (TREE_CODE (access_size) == INTEGER_CST)
+ if (byte_off != 0
+ && TREE_CODE (access_size) == INTEGER_CST
+ && !integer_zerop (access_size))
{
- /* For naturally aligned accesses print the nonzero offset
- in units of the accessed type, in the form of an index.
- For unaligned accesses also print the residual byte offset. */
offset_int asize = wi::to_offset (access_size);
- offset_int szlg2 = wi::floor_log2 (asize);
-
- elt_idx = byte_off >> szlg2;
- byte_off = byte_off - (elt_idx << szlg2);
+ elt_idx = byte_off / asize;
+ byte_off = byte_off % asize;
}
/* True to include a cast to the accessed type. */
- const bool access_cast = VOID_TYPE_P (arg_type)
- || TYPE_MAIN_VARIANT (access_type) != TYPE_MAIN_VARIANT (arg_type);
+ const bool access_cast
+ = ((op && op != TREE_OPERAND (arg, 0))
+ || VOID_TYPE_P (arg_type)
+ || !lang_hooks.types_compatible_p (access_type, arg_type));
+ const bool has_off = byte_off != 0 || (op && op != TREE_OPERAND (arg, 0));
- if (byte_off != 0)
+ if (has_off && (byte_off != 0 || !array_ref_only))
{
/* When printing the byte offset for a pointer to a type of
a different size than char, include a cast to char* first,
before printing the cast to a pointer to the accessed type. */
- offset_int arg_size = 0;
- if (tree size = TYPE_SIZE (arg_type))
- arg_size = wi::to_offset (size);
- if (arg_size != BITS_PER_UNIT)
+ tree size = TYPE_SIZE (arg_type);
+ if (size == NULL_TREE
+ || TREE_CODE (size) != INTEGER_CST
+ || wi::to_wide (size) != BITS_PER_UNIT)
char_cast = true;
}
if (elt_idx == 0)
- {
- if (!addr)
- pp_c_star (pp);
- }
+ pp_c_star (pp);
else if (access_cast || char_cast)
pp_c_left_paren (pp);
with the type of the referenced object (or if the object
is typeless). */
pp_c_left_paren (pp);
- pp->type_id (access_type);
- pp_c_star (pp);
+ pp->type_id (build_pointer_type (access_type));
pp_c_right_paren (pp);
}
- if (byte_off != 0)
+ if (has_off)
pp_c_left_paren (pp);
if (char_cast)
{
- /* Include a cast to char*. */
+ /* Include a cast to char *. */
pp_c_left_paren (pp);
- pp->type_id (char_type_node);
- pp_c_star (pp);
+ pp->type_id (string_type_node);
pp_c_right_paren (pp);
}
pp->unary_expression (arg);
+ if (op && op != TREE_OPERAND (arg, 0))
+ {
+ auto_vec<tree, 16> refs;
+ tree ref;
+ unsigned i;
+ bool array_refs = true;
+ for (ref = op; ref != TREE_OPERAND (arg, 0); ref = TREE_OPERAND (ref, 0))
+ refs.safe_push (ref);
+ FOR_EACH_VEC_ELT_REVERSE (refs, i, ref)
+ if (array_refs && TREE_CODE (ref) == ARRAY_REF)
+ {
+ pp_c_left_bracket (pp);
+ pp->expression (TREE_OPERAND (ref, 1));
+ pp_c_right_bracket (pp);
+ }
+ else
+ {
+ if (array_refs)
+ {
+ array_refs = false;
+ pp_string (pp, " + offsetof");
+ pp_c_left_paren (pp);
+ pp->type_id (TREE_TYPE (TREE_OPERAND (ref, 0)));
+ pp_comma (pp);
+ }
+ else if (TREE_CODE (ref) == COMPONENT_REF)
+ pp_c_dot (pp);
+ if (TREE_CODE (ref) == COMPONENT_REF)
+ pp->expression (TREE_OPERAND (ref, 1));
+ else
+ {
+ pp_c_left_bracket (pp);
+ pp->expression (TREE_OPERAND (ref, 1));
+ pp_c_right_bracket (pp);
+ }
+ }
+ if (!array_refs)
+ pp_c_right_paren (pp);
+ }
+
if (byte_off != 0)
{
pp_space (pp);
pp_space (pp);
tree off = wide_int_to_tree (ssizetype, byte_off);
pp->constant (off);
- pp_c_right_paren (pp);
}
+
+ if (has_off)
+ pp_c_right_paren (pp);
+
if (elt_idx != 0)
{
if (access_cast || char_cast)
pp_c_right_paren (pp);
- if (addr)
- {
- pp_space (pp);
- pp_plus (pp);
- pp_space (pp);
- }
- else
- pp_c_left_bracket (pp);
+ pp_c_left_bracket (pp);
tree idx = wide_int_to_tree (ssizetype, elt_idx);
pp->constant (idx);
- if (!addr)
- pp_c_right_bracket (pp);
+ pp_c_right_bracket (pp);
}
}
} \
typedef void dummy_type
-T (int, 0, 0); // { dg-warning "'\\*\\(int\\*\\)p' is used uninitialized" }
-T (int, 0, 1); // { dg-warning "'\\*\\(int\\*\\)\\(\\(char\\*\\)p \\+ 1\\)'" }
-T (int, 0, 2); // { dg-warning "'\\*\\(int\\*\\)\\(\\(char\\*\\)p \\+ 2\\)'" }
-T (int, 0, 3); // { dg-warning "'\\*\\(int\\*\\)\\(\\(char\\*\\)p \\+ 3\\)'" }
-T (int, 0, 4); // { dg-warning "'\\(\\(int\\*\\)p\\)\\\[1]'" }
-T (int, 0, 5); // { dg-warning "'\\(\\(int\\*\\)\\(\\(char\\*\\)p \\+ 1\\)\\)\\\[1]'" }
-T (int, 0, 6); // { dg-warning "'\\(\\(int\\*\\)\\(\\(char\\*\\)p \\+ 2\\)\\)\\\[1]'" }
-T (int, 0, 7); // { dg-warning "'\\(\\(int\\*\\)\\(\\(char\\*\\)p \\+ 3\\)\\)\\\[1]'" }
-T (int, 0, 8); // { dg-warning "'\\(\\(int\\*\\)p\\)\\\[2]'" }
-T (int, 0, 9); // { dg-warning "'\\(\\(int\\*\\)\\(\\(char\\*\\)p \\+ 1\\)\\)\\\[2]'" }
+T (int, 0, 0); // { dg-warning "'\\*\\(int \\*\\)p' is used uninitialized" }
+T (int, 0, 1); // { dg-warning "'\\*\\(int \\*\\)\\(\\(char \\*\\)p \\+ 1\\)'" }
+T (int, 0, 2); // { dg-warning "'\\*\\(int \\*\\)\\(\\(char \\*\\)p \\+ 2\\)'" }
+T (int, 0, 3); // { dg-warning "'\\*\\(int \\*\\)\\(\\(char \\*\\)p \\+ 3\\)'" }
+T (int, 0, 4); // { dg-warning "'\\(\\(int \\*\\)p\\)\\\[1]'" }
+T (int, 0, 5); // { dg-warning "'\\(\\(int \\*\\)\\(\\(char \\*\\)p \\+ 1\\)\\)\\\[1]'" }
+T (int, 0, 6); // { dg-warning "'\\(\\(int \\*\\)\\(\\(char \\*\\)p \\+ 2\\)\\)\\\[1]'" }
+T (int, 0, 7); // { dg-warning "'\\(\\(int \\*\\)\\(\\(char \\*\\)p \\+ 3\\)\\)\\\[1]'" }
+T (int, 0, 8); // { dg-warning "'\\(\\(int \\*\\)p\\)\\\[2]'" }
+T (int, 0, 9); // { dg-warning "'\\(\\(int \\*\\)\\(\\(char \\*\\)p \\+ 1\\)\\)\\\[2]'" }
-T (int, 1, 0); // { dg-warning "'\\(\\(int\\*\\)p\\)\\\[1]' is used uninitialized" }
-T (int, 1, 1); // { dg-warning "'\\(\\(int\\*\\)\\(\\(char\\*\\)p \\+ 1\\)\\)\\\[1]'" }
-T (int, 1, 2); // { dg-warning "'\\(\\(int\\*\\)\\(\\(char\\*\\)p \\+ 2\\)\\)\\\[1]'" }
-T (int, 1, 3); // { dg-warning "'\\(\\(int\\*\\)\\(\\(char\\*\\)p \\+ 3\\)\\)\\\[1]'" }
-T (int, 1, 4); // { dg-warning "'\\(\\(int\\*\\)p\\)\\\[2]'" }
-T (int, 1, 5); // { dg-warning "'\\(\\(int\\*\\)\\(\\(char\\*\\)p \\+ 1\\)\\)\\\[2]'" }
-T (int, 1, 6); // { dg-warning "'\\(\\(int\\*\\)\\(\\(char\\*\\)p \\+ 2\\)\\)\\\[2]'" }
-T (int, 1, 7); // { dg-warning "'\\(\\(int\\*\\)\\(\\(char\\*\\)p \\+ 3\\)\\)\\\[2]'" }
-T (int, 1, 8); // { dg-warning "'\\(\\(int\\*\\)p\\)\\\[3]'" }
-T (int, 1, 9); // { dg-warning "'\\(\\(int\\*\\)\\(\\(char\\*\\)p \\+ 1\\)\\)\\\[3]'" }
+T (int, 1, 0); // { dg-warning "'\\(\\(int \\*\\)p\\)\\\[1]' is used uninitialized" }
+T (int, 1, 1); // { dg-warning "'\\(\\(int \\*\\)\\(\\(char \\*\\)p \\+ 1\\)\\)\\\[1]'" }
+T (int, 1, 2); // { dg-warning "'\\(\\(int \\*\\)\\(\\(char \\*\\)p \\+ 2\\)\\)\\\[1]'" }
+T (int, 1, 3); // { dg-warning "'\\(\\(int \\*\\)\\(\\(char \\*\\)p \\+ 3\\)\\)\\\[1]'" }
+T (int, 1, 4); // { dg-warning "'\\(\\(int \\*\\)p\\)\\\[2]'" }
+T (int, 1, 5); // { dg-warning "'\\(\\(int \\*\\)\\(\\(char \\*\\)p \\+ 1\\)\\)\\\[2]'" }
+T (int, 1, 6); // { dg-warning "'\\(\\(int \\*\\)\\(\\(char \\*\\)p \\+ 2\\)\\)\\\[2]'" }
+T (int, 1, 7); // { dg-warning "'\\(\\(int \\*\\)\\(\\(char \\*\\)p \\+ 3\\)\\)\\\[2]'" }
+T (int, 1, 8); // { dg-warning "'\\(\\(int \\*\\)p\\)\\\[3]'" }
+T (int, 1, 9); // { dg-warning "'\\(\\(int \\*\\)\\(\\(char \\*\\)p \\+ 1\\)\\)\\\[3]'" }
#undef T
#define T(Type, idx, off) \
} \
typedef void dummy_type
-T (int, 0, 0); // { dg-warning "'\\*\\(int\\*\\)a' is used uninitialized" }
-T (int, 0, 1); // { dg-warning "'\\*\\(int\\*\\)\\(a \\+ 1\\)'" }
-T (int, 0, 2); // { dg-warning "'\\*\\(int\\*\\)\\(a \\+ 2\\)'" }
-T (int, 0, 3); // { dg-warning "'\\*\\(int\\*\\)\\(a \\+ 3\\)'" }
-T (int, 0, 4); // { dg-warning "'\\(\\(int\\*\\)a\\)\\\[1]'" }
-T (int, 0, 5); // { dg-warning "'\\(\\(int\\*\\)\\(a \\+ 1\\)\\)\\\[1]'" }
-T (int, 0, 6); // { dg-warning "'\\(\\(int\\*\\)\\(a \\+ 2\\)\\)\\\[1]'" }
-T (int, 0, 7); // { dg-warning "'\\(\\(int\\*\\)\\(a \\+ 3\\)\\)\\\[1]'" }
-T (int, 0, 8); // { dg-warning "'\\(\\(int\\*\\)a\\)\\\[2]'" }
-T (int, 0, 9); // { dg-warning "'\\(\\(int\\*\\)\\(a \\+ 1\\)\\)\\\[2]'" }
+T (int, 0, 0); // { dg-warning "'\\*\\(int \\*\\)a' is used uninitialized" }
+T (int, 0, 1); // { dg-warning "'\\*\\(int \\*\\)\\(\\(char \\*\\)a \\+ 1\\)'" }
+T (int, 0, 2); // { dg-warning "'\\*\\(int \\*\\)\\(\\(char \\*\\)a \\+ 2\\)'" }
+T (int, 0, 3); // { dg-warning "'\\*\\(int \\*\\)\\(\\(char \\*\\)a \\+ 3\\)'" }
+T (int, 0, 4); // { dg-warning "'\\(\\(int \\*\\)a\\)\\\[1]'" }
+T (int, 0, 5); // { dg-warning "'\\(\\(int \\*\\)\\(\\(char \\*\\)a \\+ 1\\)\\)\\\[1]'" }
+T (int, 0, 6); // { dg-warning "'\\(\\(int \\*\\)\\(\\(char \\*\\)a \\+ 2\\)\\)\\\[1]'" }
+T (int, 0, 7); // { dg-warning "'\\(\\(int \\*\\)\\(\\(char \\*\\)a \\+ 3\\)\\)\\\[1]'" }
+T (int, 0, 8); // { dg-warning "'\\(\\(int \\*\\)a\\)\\\[2]'" }
+T (int, 0, 9); // { dg-warning "'\\(\\(int \\*\\)\\(\\(char \\*\\)a \\+ 1\\)\\)\\\[2]'" }
-T (int, 1, 0); // { dg-warning "'\\(\\(int\\*\\)a\\)\\\[1]' is used uninitialized" }
-T (int, 1, 1); // { dg-warning "'\\(\\(int\\*\\)\\(a \\+ 1\\)\\)\\\[1]'" }
-T (int, 1, 2); // { dg-warning "'\\(\\(int\\*\\)\\(a \\+ 2\\)\\)\\\[1]'" }
-T (int, 1, 3); // { dg-warning "'\\(\\(int\\*\\)\\(a \\+ 3\\)\\)\\\[1]'" }
-T (int, 1, 4); // { dg-warning "'\\(\\(int\\*\\)a\\)\\\[2]'" }
-T (int, 1, 5); // { dg-warning "'\\(\\(int\\*\\)\\(a \\+ 1\\)\\)\\\[2]'" }
-T (int, 1, 6); // { dg-warning "'\\(\\(int\\*\\)\\(a \\+ 2\\)\\)\\\[2]'" }
-T (int, 1, 7); // { dg-warning "'\\(\\(int\\*\\)\\(a \\+ 3\\)\\)\\\[2]'" }
-T (int, 1, 8); // { dg-warning "'\\(\\(int\\*\\)a\\)\\\[3]'" }
-T (int, 1, 9); // { dg-warning "'\\(\\(int\\*\\)\\(a \\+ 1\\)\\)\\\[3]'" }
+T (int, 1, 0); // { dg-warning "'\\(\\(int \\*\\)a\\)\\\[1]' is used uninitialized" }
+T (int, 1, 1); // { dg-warning "'\\(\\(int \\*\\)\\(\\(char \\*\\)a \\+ 1\\)\\)\\\[1]'" }
+T (int, 1, 2); // { dg-warning "'\\(\\(int \\*\\)\\(\\(char \\*\\)a \\+ 2\\)\\)\\\[1]'" }
+T (int, 1, 3); // { dg-warning "'\\(\\(int \\*\\)\\(\\(char \\*\\)a \\+ 3\\)\\)\\\[1]'" }
+T (int, 1, 4); // { dg-warning "'\\(\\(int \\*\\)a\\)\\\[2]'" }
+T (int, 1, 5); // { dg-warning "'\\(\\(int \\*\\)\\(\\(char \\*\\)a \\+ 1\\)\\)\\\[2]'" }
+T (int, 1, 6); // { dg-warning "'\\(\\(int \\*\\)\\(\\(char \\*\\)a \\+ 2\\)\\)\\\[2]'" }
+T (int, 1, 7); // { dg-warning "'\\(\\(int \\*\\)\\(\\(char \\*\\)a \\+ 3\\)\\)\\\[2]'" }
+T (int, 1, 8); // { dg-warning "'\\(\\(int \\*\\)a\\)\\\[3]'" }
+T (int, 1, 9); // { dg-warning "'\\(\\(int \\*\\)\\(\\(char \\*\\)a \\+ 1\\)\\)\\\[3]'" }