+2017-06-02 Bernd Edlinger <bernd.edlinger@hotmail.de>
+
+ * doc/invoke.texi: Document the -Wsizeof-pointer-div warning.
+
2017-06-01 Bernd Edlinger <bernd.edlinger@hotmail.de>
* config/i386/i386.c (x86_64_ms_sysv_extra_clobbered_registers): Make
+2017-06-02 Bernd Edlinger <bernd.edlinger@hotmail.de>
+
+ * c.opt (Wsizeof-pointer-div): New warning option.
+
2017-06-01 Volker Reichelt <v.reichelt@netcologne.de>
* c.opt (Wcatch-value): New shortcut for Wcatch-value=1.
C++ ObjC++ Var(warn_sized_deallocation) Warning EnabledBy(Wextra)
Warn about missing sized deallocation functions.
+Wsizeof-pointer-div
+C ObjC C++ ObjC++ Var(warn_sizeof_pointer_div) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall)
+Warn about suspicious divisions of two sizeof expressions that don't work correctly with pointers.
+
Wsizeof-pointer-memaccess
C ObjC C++ ObjC++ Var(warn_sizeof_pointer_memaccess) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall)
Warn about suspicious length parameters to certain string functions if the argument uses sizeof.
+2017-06-02 Bernd Edlinger <bernd.edlinger@hotmail.de>
+
+ * c-parser.c (c_parser_binary_expression): Implement the
+ -Wsizeof_pointer_div warning.
+ (c_parser_postfix_expression): Allow SIZEOF_EXPR as expr.original_code
+ from a parenthesized expression.
+ (c_parser_expr_list): Use c_last_sizeof_loc.
+ * c-tree.h (c_last_sizeof_loc): New external.
+ * c-typeck.c (c_last_sizeof_loc): New variable.
+ (c_expr_sizeof_expr, c_expr_sizeof_type): Assign c_last_sizeof_loc.
+
2017-05-31 Mikhail Maltsev <maltsevm@gmail.com>
PR testsuite/80580
enum tree_code op;
/* The source location of this operation. */
location_t loc;
+ /* The sizeof argument if expr.original_code == SIZEOF_EXPR. */
+ tree sizeof_arg;
} stack[NUM_PRECS];
int sp;
/* Location of the binary operator. */
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) \
+ { \
+ tree type0 = stack[sp - 1].sizeof_arg; \
+ tree type1 = stack[sp].sizeof_arg; \
+ tree first_arg = type0; \
+ if (!TYPE_P (type0)) \
+ type0 = TREE_TYPE (type0); \
+ if (!TYPE_P (type1)) \
+ type1 = TREE_TYPE (type1); \
+ if (POINTER_TYPE_P (type0) \
+ && comptypes (TREE_TYPE (type0), type1) \
+ && !(TREE_CODE (first_arg) == PARM_DECL \
+ && C_ARRAY_PARAMETER (first_arg) \
+ && warn_sizeof_array_argument)) \
+ 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"); \
+ } \
+ break; \
default: \
break; \
} \
stack[0].loc = c_parser_peek_token (parser)->location;
stack[0].expr = c_parser_cast_expression (parser, after);
stack[0].prec = PREC_NONE;
+ stack[0].sizeof_arg = c_last_sizeof_arg;
sp = 0;
while (true)
{
stack[sp].expr = c_parser_cast_expression (parser, NULL);
stack[sp].prec = oprec;
stack[sp].op = ocode;
+ stack[sp].sizeof_arg = c_last_sizeof_arg;
}
out:
while (sp > 0)
expr = c_parser_expression (parser);
if (TREE_CODE (expr.value) == MODIFY_EXPR)
TREE_NO_WARNING (expr.value) = 1;
- if (expr.original_code != C_MAYBE_CONST_EXPR)
+ if (expr.original_code != C_MAYBE_CONST_EXPR
+ && expr.original_code != SIZEOF_EXPR)
expr.original_code = ERROR_MARK;
/* Don't change EXPR.ORIGINAL_TYPE. */
location_t loc_close_paren = c_parser_peek_token (parser)->location;
vec<tree, va_gc> *orig_types;
struct c_expr expr;
location_t loc = c_parser_peek_token (parser)->location;
- location_t cur_sizeof_arg_loc = UNKNOWN_LOCATION;
unsigned int idx = 0;
ret = make_tree_vector ();
else
orig_types = make_tree_vector ();
- if (sizeof_arg != NULL
- && c_parser_next_token_is_keyword (parser, RID_SIZEOF))
- cur_sizeof_arg_loc = c_parser_peek_2nd_token (parser)->location;
if (literal_zero_mask)
c_parser_check_literal_zero (parser, literal_zero_mask, 0);
expr = c_parser_expr_no_commas (parser, NULL);
if (locations)
locations->safe_push (loc);
if (sizeof_arg != NULL
- && cur_sizeof_arg_loc != UNKNOWN_LOCATION
&& expr.original_code == SIZEOF_EXPR)
{
sizeof_arg[0] = c_last_sizeof_arg;
- sizeof_arg_loc[0] = cur_sizeof_arg_loc;
+ sizeof_arg_loc[0] = c_last_sizeof_loc;
}
while (c_parser_next_token_is (parser, CPP_COMMA))
{
c_parser_consume_token (parser);
loc = c_parser_peek_token (parser)->location;
- if (sizeof_arg != NULL
- && c_parser_next_token_is_keyword (parser, RID_SIZEOF))
- cur_sizeof_arg_loc = c_parser_peek_2nd_token (parser)->location;
- else
- cur_sizeof_arg_loc = UNKNOWN_LOCATION;
if (literal_zero_mask)
c_parser_check_literal_zero (parser, literal_zero_mask, idx + 1);
expr = c_parser_expr_no_commas (parser, NULL);
locations->safe_push (loc);
if (++idx < 3
&& sizeof_arg != NULL
- && cur_sizeof_arg_loc != UNKNOWN_LOCATION
&& expr.original_code == SIZEOF_EXPR)
{
sizeof_arg[idx] = c_last_sizeof_arg;
- sizeof_arg_loc[idx] = cur_sizeof_arg_loc;
+ sizeof_arg_loc[idx] = c_last_sizeof_loc;
}
}
if (orig_types)
extern int in_typeof;
extern tree c_last_sizeof_arg;
+extern location_t c_last_sizeof_loc;
extern struct c_switch *c_switch_stack;
/* The argument of last parsed sizeof expression, only to be tested
if expr.original_code == SIZEOF_EXPR. */
tree c_last_sizeof_arg;
+location_t c_last_sizeof_loc;
/* Nonzero if we might need to print a "missing braces around
initializer" message within this initializer. */
&expr_const_operands);
ret.value = c_sizeof (loc, TREE_TYPE (folded_expr));
c_last_sizeof_arg = expr.value;
+ c_last_sizeof_loc = loc;
ret.original_code = SIZEOF_EXPR;
ret.original_type = NULL;
if (c_vla_type_p (TREE_TYPE (folded_expr)))
type = groktypename (t, &type_expr, &type_expr_const);
ret.value = c_sizeof (loc, type);
c_last_sizeof_arg = type;
+ c_last_sizeof_loc = loc;
ret.original_code = SIZEOF_EXPR;
ret.original_type = NULL;
if ((type_expr || TREE_CODE (ret.value) == INTEGER_CST)
+2017-06-02 Bernd Edlinger <bernd.edlinger@hotmail.de>
+
+ * typeck.c (cp_build_binary_op): Implement the -Wsizeof_pointer_div
+ warning.
+
2017-06-01 Ville Voutilainen <ville.voutilainen@gmail.com>
PR c++/80812
case FLOOR_DIV_EXPR:
case ROUND_DIV_EXPR:
case EXACT_DIV_EXPR:
+ if (TREE_CODE (op0) == SIZEOF_EXPR && TREE_CODE (op1) == SIZEOF_EXPR)
+ {
+ tree type0 = TREE_OPERAND (op0, 0);
+ tree type1 = TREE_OPERAND (op1, 0);
+ tree first_arg = type0;
+ if (!TYPE_P (type0))
+ type0 = TREE_TYPE (type0);
+ if (!TYPE_P (type1))
+ type1 = TREE_TYPE (type1);
+ if (POINTER_TYPE_P (type0) && same_type_p (TREE_TYPE (type0), type1)
+ && !(TREE_CODE (first_arg) == PARM_DECL
+ && DECL_ARRAY_PARAMETER_P (first_arg)
+ && warn_sizeof_array_argument)
+ && (complain & tf_warning))
+ if (warning_at (location, 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");
+ }
+
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
|| code0 == COMPLEX_TYPE || code0 == VECTOR_TYPE)
&& (code1 == INTEGER_TYPE || code1 == REAL_TYPE
-Wshift-overflow -Wshift-overflow=@var{n} @gol
-Wshift-count-negative -Wshift-count-overflow -Wshift-negative-value @gol
-Wsign-compare -Wsign-conversion -Wfloat-conversion @gol
--Wno-scalar-storage-order @gol
+-Wno-scalar-storage-order -Wsizeof-pointer-div @gol
-Wsizeof-pointer-memaccess -Wsizeof-array-argument @gol
-Wstack-protector -Wstack-usage=@var{len} -Wstrict-aliasing @gol
-Wstrict-aliasing=n -Wstrict-overflow -Wstrict-overflow=@var{n} @gol
-Wreturn-type @gol
-Wsequence-point @gol
-Wsign-compare @r{(only in C++)} @gol
+-Wsizeof-pointer-div @gol
-Wsizeof-pointer-memaccess @gol
-Wstrict-aliasing @gol
-Wstrict-overflow=1 @gol
or vice versa. Enabled by @option{-Wextra} along with
@option{-fsized-deallocation}.
+@item -Wsizeof-pointer-div
+@opindex Wsizeof-pointer-div
+@opindex Wno-sizeof-pointer-div
+Warn for suspicious divisions of two sizeof expressions that divide
+the pointer size by the element size, which is the usual way to compute
+the array size but won't work out correctly with pointers. This warning
+warns e.g.@: about @code{sizeof (ptr) / sizeof (ptr[0])} if @code{ptr} is
+not an array, but a pointer. This warning is enabled by @option{-Wall}.
+
@item -Wsizeof-pointer-memaccess
@opindex Wsizeof-pointer-memaccess
@opindex Wno-sizeof-pointer-memaccess
+2017-06-02 Bernd Edlinger <bernd.edlinger@hotmail.de>
+
+ * c-c++-common/Wsizeof-pointer-div.c: New test.
+ * gcc.dg/Wsizeof-pointer-memaccess1.c: Add test cases with parens.
+ * gcc.dg/torture/Wsizeof-pointer-memaccess1.c: Likewise.
+ * gcc.target/i386/sse-init-v4hi-1.c: Fix test case.
+ * gcc.target/i386/sse-init-v4sf-1.c: Likewise.
+ * gcc.target/i386/sse-set-ps-1.c: Likewise.
+ * gcc.target/i386/sse2-init-v16qi-1.c: Likewise.
+ * gcc.target/i386/sse2-init-v2di-1.c: Likewise.
+ * gcc.target/i386/sse2-init-v4si-1.c: Likewise.
+ * gcc.target/i386/sse2-init-v8hi-1.c: Likewise.
+ * gcc.target/i386/sse2-set-epi32-1.c: Likewise.
+ * gcc.target/i386/sse2-set-epi64x-1.c: Likewise.
+ * gcc.target/i386/sse4_1-init-v16qi-1.c: Likewise.
+ * gcc.target/i386/sse4_1-init-v2di-1.c: Likewise.
+ * gcc.target/i386/sse4_1-init-v4sf-1.c: Likewise.
+ * gcc.target/i386/sse4_1-init-v4si-1.c: Likewise.
+ * gcc.target/i386/sse4_1-set-epi32-1.c: Likewise.
+ * gcc.target/i386/sse4_1-set-epi64x-1.c: Likewise.
+ * gcc.target/i386/sse4_1-set-ps-1.c: Likewise.
+
2017-06-01 Will Schmidt <will_schmidt@vnet.ibm.com>
* gcc.target/powerpc/fold-vec-logical-ors-longlong.c:
--- /dev/null
+/* Test -Wsizeof-pointer-div warnings. */
+/* { dg-do compile } */
+/* { dg-options "-Wall" } */
+
+int
+f1 (int *array)
+{
+ int i;
+ i = sizeof array / sizeof *array; /* { dg-warning "does not compute the number of array elements" } */
+ i += sizeof array / sizeof array[0]; /* { dg-warning "does not compute the number of array elements" } */
+ i += sizeof(array) / sizeof(*array); /* { dg-warning "does not compute the number of array elements" } */
+ i += sizeof(array) / sizeof(array[0]); /* { dg-warning "does not compute the number of array elements" } */
+ i += (sizeof(array)) / (sizeof(array[0])); /* { dg-warning "does not compute the number of array elements" } */
+ i += sizeof(array) / sizeof(int); /* { dg-warning "does not compute the number of array elements" } */
+ i += sizeof(array) / sizeof(char);
+ i += sizeof(*array) / sizeof(char);
+ i += sizeof(array[0]) / sizeof(char);
+ return i;
+}
+
+int
+f2 (void)
+{
+ int array[10];
+ int i;
+ i = sizeof array / sizeof *array;
+ i += sizeof array / sizeof array[0];
+ i += sizeof(array) / sizeof(*array);
+ i += sizeof(array) / sizeof(array[0]);
+ i += (sizeof(array)) / (sizeof(array[0]));
+ i += sizeof(array) / sizeof(int);
+ i += sizeof(array) / sizeof(char);
+ i += sizeof(*array) / sizeof(char);
+ i += sizeof(array[0]) / sizeof(char);
+ return i;
+}
+
+int
+f3 (int a[])
+{
+ return sizeof a / sizeof *a; /* { dg-warning "Wsizeof-array-argument" } */
+}
z += bcmp (x, pa2, sizeof (PTA)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" } */
z += bcmp (x, pa3, sizeof (PA)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" } */
+ z += bcmp (x, (&a), (sizeof (&a))); /* { dg-warning "call is the same expression as the second source; did you mean to remove the addressof" } */
+ z += bcmp (x, (pa1), (sizeof (pa1))); /* { dg-warning "call is the same expression as the second source; did you mean to dereference it" } */
+ z += bcmp (x, (pa2), (sizeof pa2)); /* { dg-warning "call is the same expression as the second source; did you mean to dereference it" } */
+ z += bcmp (x, (pa3), (sizeof (pa3))); /* { dg-warning "call is the same expression as the second source; did you mean to dereference it" } */
+ z += bcmp (x, (pa4), (sizeof pa4)); /* { dg-warning "call is the same expression as the second source; did you mean to dereference it" } */
+ z += bcmp (x, (pa1), (sizeof (struct A *)));/* { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" } */
+ z += bcmp (x, (pa2), (sizeof (PTA))); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" } */
+ z += bcmp (x, (pa3), (sizeof (PA))); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" } */
+
/* These are correct, no warning. */
bzero (&a, sizeof a);
bzero (&a, sizeof (a));
z += memcmp (x, pa2, sizeof (PTA)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" } */
z += memcmp (x, pa3, sizeof (PA)); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" } */
+ z += memcmp (x, (&a), (sizeof (&a))); /* { dg-warning "call is the same expression as the second source; did you mean to remove the addressof" } */
+ z += memcmp (x, (pa1), (sizeof (pa1))); /* { dg-warning "call is the same expression as the second source; did you mean to dereference it" } */
+ z += memcmp (x, (pa2), (sizeof pa2)); /* { dg-warning "call is the same expression as the second source; did you mean to dereference it" } */
+ z += memcmp (x, (pa3), (sizeof (pa3))); /* { dg-warning "call is the same expression as the second source; did you mean to dereference it" } */
+ z += memcmp (x, (pa4), (sizeof pa4)); /* { dg-warning "call is the same expression as the second source; did you mean to dereference it" } */
+ z += memcmp (x, (pa1), (sizeof (struct A *)));/* { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" } */
+ z += memcmp (x, (pa2), (sizeof (PTA))); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" } */
+ z += memcmp (x, (pa3), (sizeof (PA))); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" } */
+
/* These are correct, no warning. */
memset (&a, 0, sizeof a);
memset (&a, 0, sizeof (a));
union
{
__m64 x;
- unsigned short i[8];
+ unsigned short i[4];
} u;
unsigned int i;
u.x = x;
- for (i = 0; i < sizeof (v) / sizeof (v[0]); i++)
+ for (i = 0; i < sizeof (u) / sizeof (v[0]); i++)
if (i == j)
{
if (v[i] != u.i[i])
u.x = x;
- for (i = 0; i < sizeof (v) / sizeof (v[0]); i++)
+ for (i = 0; i < sizeof (u) / sizeof (v[0]); i++)
if (i == j)
{
if (v[i] != u.f[i])
u.x = _mm_set_ps (v[3], v[2], v[1], v[0]);
- for (i = 0; i < sizeof (v) / sizeof (v[0]); i++)
+ for (i = 0; i < sizeof (u) / sizeof (v[0]); i++)
if (v[i] != u.f[i])
{
#ifdef DEBUG
u.x = x;
- for (i = 0; i < sizeof (v) / sizeof (v[0]); i++)
+ for (i = 0; i < sizeof (u) / sizeof (v[0]); i++)
if (i == j)
{
if (v[i] != u.i[i])
u.x = x;
- for (i = 0; i < sizeof (v) / sizeof (v[0]); i++)
+ for (i = 0; i < sizeof (u) / sizeof (v[0]); i++)
if (i == j)
{
if (v[i] != u.i[i])
u.x = x;
- for (i = 0; i < sizeof (v) / sizeof (v[0]); i++)
+ for (i = 0; i < sizeof (u) / sizeof (v[0]); i++)
if (i == j)
{
if (v[i] != u.i[i])
u.x = x;
- for (i = 0; i < sizeof (v) / sizeof (v[0]); i++)
+ for (i = 0; i < sizeof (u) / sizeof (v[0]); i++)
if (i == j)
{
if (v[i] != u.i[i])
u.x = _mm_set_epi32 (v[3], v[2], v[1], v[0]);
- for (i = 0; i < sizeof (v) / sizeof (v[0]); i++)
+ for (i = 0; i < sizeof (u) / sizeof (v[0]); i++)
if (v[i] != u.i[i])
{
#ifdef DEBUG
u.x = _mm_set_epi64x (v[1], v[0]);
- for (i = 0; i < sizeof (v) / sizeof (v[0]); i++)
+ for (i = 0; i < sizeof (u) / sizeof (v[0]); i++)
if (v[i] != u.i[i])
{
#ifdef DEBUG
u.x = x;
- for (i = 0; i < sizeof (v) / sizeof (v[0]); i++)
+ for (i = 0; i < sizeof (u) / sizeof (v[0]); i++)
if (i == j)
{
if (v[i] != u.i[i])
u.x = x;
- for (i = 0; i < sizeof (v) / sizeof (v[0]); i++)
+ for (i = 0; i < sizeof (u) / sizeof (v[0]); i++)
if (i == j)
{
if (v[i] != u.i[i])
u.x = x;
- for (i = 0; i < sizeof (v) / sizeof (v[0]); i++)
+ for (i = 0; i < sizeof (u) / sizeof (v[0]); i++)
if (i == j)
{
if (v[i] != u.f[i])
u.x = x;
- for (i = 0; i < sizeof (v) / sizeof (v[0]); i++)
+ for (i = 0; i < sizeof (u) / sizeof (v[0]); i++)
if (i == j)
{
if (v[i] != u.i[i])
u.x = _mm_set_epi32 (v[3], v[2], v[1], v[0]);
- for (i = 0; i < sizeof (v) / sizeof (v[0]); i++)
+ for (i = 0; i < sizeof (u) / sizeof (v[0]); i++)
if (v[i] != u.i[i])
{
#ifdef DEBUG
u.x = _mm_set_epi64x (v[1], v[0]);
- for (i = 0; i < sizeof (v) / sizeof (v[0]); i++)
+ for (i = 0; i < sizeof (u) / sizeof (v[0]); i++)
if (v[i] != u.i[i])
{
#ifdef DEBUG
u.x = _mm_set_ps (v[3], v[2], v[1], v[0]);
- for (i = 0; i < sizeof (v) / sizeof (v[0]); i++)
+ for (i = 0; i < sizeof (u) / sizeof (v[0]); i++)
if (v[i] != u.f[i])
{
#ifdef DEBUG
+2017-06-02 Bernd Edlinger <bernd.edlinger@hotmail.de>
+
+ * testsuite/libgomp.c/pr39591-2.c: Fix test case.
+ * testsuite/libgomp.c/pr39591-3.c: Likewise.
+
2017-05-30 Jakub Jelinek <jakub@redhat.com>
PR libgomp/80822
#pragma omp task
{
int j;
- for (j = 0; j < sizeof array / sizeof array[0]; j++)
+ for (j = 0; j < 40; j++)
if (array[j] != 0x55555555)
#pragma omp atomic
err++;
#pragma omp task
{
int j;
- for (j = 0; j < sizeof array / sizeof array[0]; j++)
+ for (j = 0; j < 40; j++)
if (array[j] != 0x55555555)
#pragma omp atomic
err++;