On Thu, 14 Jan 2021, Jakub Jelinek wrote: > On Thu, Jan 14, 2021 at 10:49:42AM -0700, Martin Sebor wrote: > > > In the light of Martins patch this is probably reasonable but still > > > the general direction is wrong (which is why I didn't approve Martins > > > original patch). I'm also somewhat disappointed we're breaking this > > > so late in the cycle. > > > > So am I. I didn't test this change as exhaustively as I could and > > (in light of the poor test coverage) should have. That's my bad. > > FWIW, I did do it for the first patch (by instrumenting GCC and > > formatting every MEM_REF it came across), but it didn't occur to > > me to do it this time around. I have now completed this testing > > (it found one more ICE elsewhere that I'll fix soon). > > Ok, here is an updated patch which fixes what I found, and implements what > has been discussed on the mailing list and on IRC, i.e. if the types > are compatible as well as alias sets are same, then it prints > what c_fold_indirect_ref_for_warn managed to create, otherwise it uses > that info for printing offsets using offsetof (except when it starts > with ARRAY_REFs, because one can't have offsetof (struct T[2][2], [1][0].x.y) > > The uninit-38.c test (which was the only one I believe which had tests on the > exact spelling of MEM_REF printing) contains mainly changes to have space > before * for pointer types (as that is how the C pretty-printers normally > print types, int * rather than int*), plus what might be considered a > regression from what Martin printed, but it is actually a correctness fix. > > When the arg is a pointer with type pointer to VLA with char element type > (let's say the pointer is p), which is what happens in several of the > uninit-38.c tests, omitting the (char *) cast is incorrect, as p + 1 > is not the 1 byte after p, but pointer to the end of the VLA. > It only happened to work because of the hacks (which I don't like at all > and are dangerous, DECL_ARTIFICIAL var names with dot inside can be pretty > much anything, e.g. a lot of passes construct their helper vars from some > prefix that designates intended use of the var plus numeric suffix), where > the a.1 pointer to VLA is printed as a which if one is lucky happens to be > a variable with VLA type (rather than pointer to it), and for such vars > a + 1 is indeed &a[0] + 1 rather than &a + 1. But if we want to do this > reliably, we'd need to make sure it comes from VLA (e.g. verify that the > SSA_NAME is defined to __builtin_alloca_with_align and that there exists > a corresponding VAR_DECL with DECL_VALUE_EXPR that has the a.1 variable > in it). > > Is this ok for trunk if it passes bootstrap/regtest?
OK. Thanks, Richard. > 2021-01-14 Jakub Jelinek <ja...@redhat.com> > > PR tree-optimization/98597 > * c-pretty-print.c (c_fold_indirect_ref_for_warn): New function. > (print_mem_ref): Use it. If it returns something that has compatible > type and is TBAA compatible with zero offset, print it and return, > otherwise print it using offsetof syntax or array ref syntax. Fix up > printing if MEM_REFs first operand is ADDR_EXPR, or when the first > argument has pointer to array type. Print pointers using the standard > formatting. > > * gcc.dg/uninit-38.c: Expect a space in between type name and asterisk. > Expect for now a (char *) cast for VLAs. > * gcc.dg/uninit-40.c: New test. > > --- gcc/c-family/c-pretty-print.c.jj 2021-01-13 15:27:09.822834600 +0100 > +++ gcc/c-family/c-pretty-print.c 2021-01-14 19:02:21.299138891 +0100 > @@ -1809,6 +1809,113 @@ pp_c_call_argument_list (c_pretty_printe > 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 > @@ -1833,59 +1940,79 @@ print_mem_ref (c_pretty_printer *pp, tre > 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)) > + && 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); > > @@ -1895,25 +2022,63 @@ print_mem_ref (c_pretty_printer *pp, tre > 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); > @@ -1921,25 +2086,20 @@ print_mem_ref (c_pretty_printer *pp, tre > 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); > } > } > > --- gcc/testsuite/gcc.dg/uninit-38.c.jj 2021-01-07 09:34:09.725641679 > +0100 > +++ gcc/testsuite/gcc.dg/uninit-38.c 2021-01-14 17:43:33.442029629 +0100 > @@ -29,28 +29,28 @@ void sink (void*, ...); > } \ > 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, 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, 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]'" } > > #undef T > #define T(Type, idx, off) \ > @@ -63,25 +63,25 @@ T (int, 1, 9); // { dg-warning "'\\ > } \ > 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, 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, 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 \\*\\)\\(\\(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]'" } > --- gcc/testsuite/gcc.dg/uninit-40.c.jj 2021-01-14 13:17:58.483432786 > +0100 > +++ gcc/testsuite/gcc.dg/uninit-40.c 2021-01-14 19:03:08.039606122 +0100 > @@ -0,0 +1,50 @@ > +/* PR tree-optimization/98597 */ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -Wuninitialized" } */ > + > +union U { double d; int i; float f; }; > +struct S { char a; int b; char c; unsigned d; union U e; int f[3]; unsigned > g[3]; }; > +struct T { char t; struct S u; int v; }; > +typedef short V[2][2]; > +void baz (V *); > + > +static inline int > +bar (char *p) > +{ > + return *(int *) p; > +} > + > +void > +foo (int *q) > +{ > + struct T t; > + t.t = 1; > + t.u.c = 2; > + char *pt = (char *) &t; > + q[0] = bar (pt + __builtin_offsetof (struct T, u.b)); /* { dg-warning > "'t\\.u\\.b' is used uninitialized" } */ > + q[1] = bar (pt + __builtin_offsetof (struct T, u.e)); /* { dg-warning > "'\\*\\(int \\*\\)\\(\\(char \\*\\)&t \\+ offsetof\\(struct T, u\\.e\\)\\)' > is used uninitialized" } */ > + q[2] = bar (pt + __builtin_offsetof (struct T, v)); /* { dg-warning > "'t\\.v' is used uninitialized" } */ > + q[3] = bar (pt + __builtin_offsetof (struct T, u.d)); /* { dg-warning > "'\\*\\(int \\*\\)\\(\\(char \\*\\)&t \\+ offsetof\\(struct T, u\\.d\\)\\)' > is used uninitialized" } */ > + q[4] = bar (pt + __builtin_offsetof (struct T, u.f[2])); /* { dg-warning > "'t\\.u\\.f\\\[2\\\]' is used uninitialized" } */ > + q[5] = bar (pt + __builtin_offsetof (struct T, u.g[2])); /* { dg-warning > "'\\*\\(int \\*\\)\\(\\(char \\*\\)&t \\+ offsetof\\(struct T, > u\\.g\\\[2\\\]\\)\\)' is used uninitialized" } */ > + int s[3]; > + s[0] = 1; > + char *ps = (char *) s; > + q[6] = bar (ps + sizeof (int)); /* { dg-warning > "'s\\\[1\\\]' is used uninitialized" } */ > + unsigned w[2][2]; > + w[0][0] = 1; > + char *pw = (char *) w; > + q[7] = bar (pw + 3 * sizeof (unsigned)); /* { dg-warning > "'\\*\\(int \\*\\)\\(&w\\\[1\\\]\\\[1\\\]\\)' is used uninitialized" } */ > + struct T x[3][3]; > + x[0][0].t = 1; > + char *px = (char *) x; > + q[8] = bar (px + 5 * sizeof (struct T) + __builtin_offsetof (struct T, > u.b)); /* { dg-warning "'x\\\[1\\\]\\\[2\\\]\\.u\\.b' is used > uninitialized" } */ > + q[9] = bar (px + 6 * sizeof (struct T) + __builtin_offsetof (struct T, > u.d)); /* { dg-warning "'\\*\\(int \\*\\)\\(\\(char > \\*\\)&x\\\[2\\\]\\\[0\\\] \\+ offsetof\\(struct T, u\\.d\\)\\)' is used > uninitialized" } */ > +#if defined(__i386__) || defined(__x86_64__) > + /* memcpy folding is too target dependent to test it everywhere. */ > + V u[2], v[2]; > + u[0][0][0] = 1; > + __builtin_memcpy (&v[1], &u[1], sizeof (V)); /* { dg-warning > "'\\*\\(\(long \)?long unsigned int > \\*\\)\\(&u\\\[1\\\]\\\[0\\\]\\\[0\\\]\\)' is used uninitialized" "" { target > i?86-*-* x86_64-*-* } } */ > + baz (&v[1]); > +#endif > +} > > > Jakub > > -- Richard Biener <rguent...@suse.de> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg, Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)