aboutsummaryrefslogtreecommitdiff
path: root/gcc/c/c-parser.c
diff options
context:
space:
mode:
authorMarek Polacek <polacek@redhat.com>2020-09-11 16:19:08 -0400
committerMarek Polacek <polacek@redhat.com>2020-10-23 15:07:10 -0400
commit83f83ddfe0fe41c9b553850d4ababd5089df8332 (patch)
tree5c5f458450f7b65c5c50e64a0b9603d01de6b681 /gcc/c/c-parser.c
parent757ba6653c2699761c2243e0194749a6695112d8 (diff)
downloadgcc-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.c48
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;