diff options
author | Marek Polacek <polacek@redhat.com> | 2020-09-11 16:19:08 -0400 |
---|---|---|
committer | Marek Polacek <polacek@redhat.com> | 2020-10-23 15:07:10 -0400 |
commit | 83f83ddfe0fe41c9b553850d4ababd5089df8332 (patch) | |
tree | 5c5f458450f7b65c5c50e64a0b9603d01de6b681 /gcc/c/c-parser.c | |
parent | 757ba6653c2699761c2243e0194749a6695112d8 (diff) | |
download | gcc-83f83ddfe0fe41c9b553850d4ababd5089df8332.zip gcc-83f83ddfe0fe41c9b553850d4ababd5089df8332.tar.gz gcc-83f83ddfe0fe41c9b553850d4ababd5089df8332.tar.bz2 |
c, c++: Implement -Wsizeof-array-div [PR91741]
This patch implements a new warning, -Wsizeof-array-div. It warns about
code like
int arr[10];
sizeof (arr) / sizeof (short);
where we have a division of two sizeof expressions, where the first
argument is an array, and the second sizeof does not equal the size
of the array element. See e.g. <https://www.viva64.com/en/examples/v706/>.
Clang makes it possible to suppress the warning by parenthesizing the
second sizeof like this:
sizeof (arr) / (sizeof (short));
so I followed suit. In the C++ FE this was rather easy, because
finish_parenthesized_expr already set TREE_NO_WARNING. In the C FE
I've added a new tree code, PAREN_SIZEOF_EXPR, to discern between the
non-() and () versions.
This warning is enabled by -Wall. An example of the output:
x.c:5:23: warning: expression does not compute the number of elements in this array; element type is ‘int’, not ‘short int’ [-Wsizeof-array-div]
5 | return sizeof (arr) / sizeof (short);
| ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~
x.c:5:25: note: add parentheses around ‘sizeof (short int)’ to silence this warning
5 | return sizeof (arr) / sizeof (short);
| ^~~~~~~~~~~~~~
| ( )
x.c:4:7: note: array ‘arr’ declared here
4 | int arr[10];
| ^~~
gcc/c-family/ChangeLog:
PR c++/91741
* c-common.c (verify_tree): Handle PAREN_SIZEOF_EXPR.
(c_common_init_ts): Likewise.
* c-common.def (PAREN_SIZEOF_EXPR): New tree code.
* c-common.h (maybe_warn_sizeof_array_div): Declare.
* c-warn.c (sizeof_pointer_memaccess_warning): Unwrap NOP_EXPRs.
(maybe_warn_sizeof_array_div): New function.
* c.opt (Wsizeof-array-div): New option.
gcc/c/ChangeLog:
PR c++/91741
* c-parser.c (c_parser_binary_expression): Implement -Wsizeof-array-div.
(c_parser_postfix_expression): Set PAREN_SIZEOF_EXPR.
(c_parser_expr_list): Handle PAREN_SIZEOF_EXPR like SIZEOF_EXPR.
* c-tree.h (char_type_p): Declare.
* c-typeck.c (char_type_p): No longer static.
gcc/cp/ChangeLog:
PR c++/91741
* typeck.c (cp_build_binary_op): Implement -Wsizeof-array-div.
gcc/ChangeLog:
PR c++/91741
* doc/invoke.texi: Document -Wsizeof-array-div.
gcc/testsuite/ChangeLog:
PR c++/91741
* c-c++-common/Wsizeof-pointer-div.c: Add dg-warning.
* c-c++-common/Wsizeof-array-div1.c: New test.
* g++.dg/warn/Wsizeof-array-div1.C: New test.
* g++.dg/warn/Wsizeof-array-div2.C: New test.
Diffstat (limited to 'gcc/c/c-parser.c')
-rw-r--r-- | gcc/c/c-parser.c | 48 |
1 files changed, 30 insertions, 18 deletions
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 7d58356..b6a7ef4 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -7876,7 +7876,7 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after, enum tree_code op; /* The source location of this operation. */ location_t loc; - /* The sizeof argument if expr.original_code == SIZEOF_EXPR. */ + /* The sizeof argument if expr.original_code == {PAREN_,}SIZEOF_EXPR. */ tree sizeof_arg; } stack[NUM_PRECS]; int sp; @@ -7894,9 +7894,11 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after, c_inhibit_evaluation_warnings -= (stack[sp - 1].expr.value \ == truthvalue_true_node); \ break; \ - case TRUNC_DIV_EXPR: \ - if (stack[sp - 1].expr.original_code == SIZEOF_EXPR \ - && stack[sp].expr.original_code == SIZEOF_EXPR) \ + case TRUNC_DIV_EXPR: \ + if ((stack[sp - 1].expr.original_code == SIZEOF_EXPR \ + || stack[sp - 1].expr.original_code == PAREN_SIZEOF_EXPR) \ + && (stack[sp].expr.original_code == SIZEOF_EXPR \ + || stack[sp].expr.original_code == PAREN_SIZEOF_EXPR)) \ { \ tree type0 = stack[sp - 1].sizeof_arg; \ tree type1 = stack[sp].sizeof_arg; \ @@ -7910,18 +7912,23 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after, && !(TREE_CODE (first_arg) == PARM_DECL \ && C_ARRAY_PARAMETER (first_arg) \ && warn_sizeof_array_argument)) \ - { \ - auto_diagnostic_group d; \ - if (warning_at (stack[sp].loc, OPT_Wsizeof_pointer_div, \ - "division %<sizeof (%T) / sizeof (%T)%> " \ - "does not compute the number of array " \ - "elements", \ - type0, type1)) \ - if (DECL_P (first_arg)) \ - inform (DECL_SOURCE_LOCATION (first_arg), \ - "first %<sizeof%> operand was declared here"); \ - } \ - } \ + { \ + auto_diagnostic_group d; \ + if (warning_at (stack[sp].loc, OPT_Wsizeof_pointer_div, \ + "division %<sizeof (%T) / sizeof (%T)%> " \ + "does not compute the number of array " \ + "elements", \ + type0, type1)) \ + if (DECL_P (first_arg)) \ + inform (DECL_SOURCE_LOCATION (first_arg), \ + "first %<sizeof%> operand was declared here"); \ + } \ + else if (TREE_CODE (type0) == ARRAY_TYPE \ + && !char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type0))) \ + && stack[sp].expr.original_code != PAREN_SIZEOF_EXPR) \ + maybe_warn_sizeof_array_div (stack[sp].loc, first_arg, type0, \ + stack[sp].sizeof_arg, type1); \ + } \ break; \ default: \ break; \ @@ -9177,6 +9184,9 @@ c_parser_postfix_expression (c_parser *parser) if (expr.original_code != C_MAYBE_CONST_EXPR && expr.original_code != SIZEOF_EXPR) expr.original_code = ERROR_MARK; + /* Remember that we saw ( ) around the sizeof. */ + if (expr.original_code == SIZEOF_EXPR) + expr.original_code = PAREN_SIZEOF_EXPR; /* Don't change EXPR.ORIGINAL_TYPE. */ location_t loc_close_paren = c_parser_peek_token (parser)->location; set_c_expr_source_range (&expr, loc_open_paren, loc_close_paren); @@ -10792,7 +10802,8 @@ c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p, if (locations) locations->safe_push (expr.get_location ()); if (sizeof_arg != NULL - && expr.original_code == SIZEOF_EXPR) + && (expr.original_code == SIZEOF_EXPR + || expr.original_code == PAREN_SIZEOF_EXPR)) { sizeof_arg[0] = c_last_sizeof_arg; sizeof_arg_loc[0] = c_last_sizeof_loc; @@ -10815,7 +10826,8 @@ c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p, locations->safe_push (expr.get_location ()); if (++idx < 3 && sizeof_arg != NULL - && expr.original_code == SIZEOF_EXPR) + && (expr.original_code == SIZEOF_EXPR + || expr.original_code == PAREN_SIZEOF_EXPR)) { sizeof_arg[idx] = c_last_sizeof_arg; sizeof_arg_loc[idx] = c_last_sizeof_loc; |