PR c++/95768 - pretty-printer ICE on -Wuninitialized with allocated storage gcc/cp/ChangeLog: PR c++/95768 * error.c (dump_expr): Handle sizeless operand types such as void*. gcc/testsuite/ChangeLog: PR c++/95768 * g++.dg/pr95768.C: New test. diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 0d6375e5e14..ea1f3232e3d 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -2374,32 +2374,63 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags) break; case MEM_REF: - if (TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR - && integer_zerop (TREE_OPERAND (t, 1))) - dump_expr (pp, TREE_OPERAND (TREE_OPERAND (t, 0), 0), flags); - else - { - pp_cxx_star (pp); - if (!integer_zerop (TREE_OPERAND (t, 1))) - { - pp_cxx_left_paren (pp); - if (!integer_onep (TYPE_SIZE_UNIT - (TREE_TYPE (TREE_TYPE (TREE_OPERAND (t, 0)))))) - { - pp_cxx_left_paren (pp); - dump_type (pp, ptr_type_node, flags); - pp_cxx_right_paren (pp); - } - } - dump_expr (pp, TREE_OPERAND (t, 0), flags); - if (!integer_zerop (TREE_OPERAND (t, 1))) - { - pp_cxx_ws_string (pp, "+"); - dump_expr (pp, fold_convert (ssizetype, TREE_OPERAND (t, 1)), - flags); - pp_cxx_right_paren (pp); - } - } + { + tree type = TREE_TYPE (t); + tree arg = TREE_OPERAND (t, 0); + tree offset = TREE_OPERAND (t, 1); + bool zero_offset = integer_zerop (offset); + + if (TREE_CODE (arg) == ADDR_EXPR && zero_offset) + dump_expr (pp, TREE_OPERAND (arg, 0), flags); + else + { + pp_cxx_star (pp); + if (!zero_offset) + { + pp_cxx_left_paren (pp); + pp_cxx_left_paren (pp); + dump_type (pp, type, flags); + pp_cxx_star (pp); + pp_cxx_right_paren (pp); + + bool byte_offset = true; + + if (tree size = TYPE_SIZE_UNIT (type)) + { + /* For naturally aligned accesses print the nonzero + offset in units of the access type. For unaligned + accesses print a byte offset instead. */ + offset_int wsiz = wi::to_offset (size); + offset_int woff = wi::to_offset (offset); + offset_int szlg2 = wi::floor_log2 (wsiz); + offset_int eltoff = woff >> szlg2; + if (eltoff << szlg2 == woff) + { + offset = wide_int_to_tree (ssizetype, eltoff); + byte_offset = false; + } + } + + if (byte_offset) + { + /* When printing the byte offset include a cast to + a character type first, before printing the cast + to the access type. */ + pp_cxx_left_paren (pp); + dump_type (pp, char_type_node, flags); + pp_cxx_star (pp); + pp_cxx_right_paren (pp); + } + } + dump_expr (pp, arg, flags); + if (!zero_offset) + { + pp_cxx_ws_string (pp, "+"); + dump_expr (pp, fold_convert (ssizetype, offset), flags); + pp_cxx_right_paren (pp); + } + } + } break; case NEGATE_EXPR: diff --git a/gcc/testsuite/g++.dg/pr95768.C b/gcc/testsuite/g++.dg/pr95768.C new file mode 100644 index 00000000000..23e6988b410 --- /dev/null +++ b/gcc/testsuite/g++.dg/pr95768.C @@ -0,0 +1,32 @@ +/* PR c++/95768 - pretty-printer ICE on -Wuninitialized with allocated storage + { dg-do compile } + { dg-options "-O2 -Wall" } */ + +extern "C" void *malloc (__SIZE_TYPE__); + +struct f +{ + int i; + static int e (int); + void operator= (int) { e (i); } +}; + +struct m { + int i; + f length; +}; + +struct n { + m *o() { return (m *)this; } +}; + +struct p { + n *header; + p () { + header = (n *)malloc (0); + m b = *header->o(); // { dg-warning "'\\*\\(\\(int\\*\\)<\[a-z\]+> \\+1\\)' is used uninitialized" } + b.length = 0; + } +}; + +void detach2() { p(); } diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-11.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-11.C new file mode 100644 index 00000000000..6f8a4586adf --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-11.C @@ -0,0 +1,40 @@ +/* Verify that -Wuninitialized warnings about accesses to objects via + pointers and offsets mention valid expressions. + { dg-do compile } + { dg-options "-O2 -Wall" } */ + +typedef __INT16_TYPE__ int16_t; +typedef __INT32_TYPE__ int32_t; + +void sink (int); + +/* Verify properly aligned accesses at offsets that are multiples of + the access size. */ + +void test_aligned (void) +{ + char *p1 = (char*)__builtin_malloc (32); + p1 += sizeof (int32_t); + + int16_t *p2 = (int16_t*)p1; + sink (p2[1]); // { dg-warning "'\\\*\\\(\\\(int16_t\\\*\\\)p1 \\\+ *3\\\)' is used uninitialized" } + + int32_t *p4 = (int32_t*)p1; + sink (p4[1]); // { dg-warning "'\\\*\\\(\\\(int32_t\\\*\\\)p1 \\\+ *2\\\)' is used uninitialized" } +} + + +/* Verify misaligned accesses at offsets that aren't multiples of + the access size. */ + +void test_misaligned (void) +{ + char *p1 = (char*)__builtin_malloc (32); + p1 += 1; + + int16_t *p2 = (int16_t*)p1; + sink (p2[1]); // { dg-warning "'\\\*\\\(\\\(int16_t\\\*\\\)\\\(char\\\*\\\)p1 \\\+ *3\\\)' is used uninitialized" } + + int32_t *p4 = (int32_t*)p1; + sink (p4[1]); // { dg-warning "'\\\*\\\(\\\(int32_t\\\*\\)\\\(char\\\*\\\)p1 \\\+ *5\\\)' is used uninitialized" } +}