Bootstrapped and regression tested on x86_64.
c: fix wrong code with counted_by attribute [PR123569]
For an access to a member of pointer type with counted_by attribute,
the .ACCESS_WITH_SIZE internal function is inserted at certain places
before reading the pointer. This leads to wrong code for increment
and decrement operations. For now, do not instrument these accesses
by using default_function_array_conversion instead of
default_function_array_read_conversion and by calling mark_exp_read
directly. Code to conditionally undo the effect of mark_exp_read can
be simplified.
PR c/123569
gcc/c/ChangeLog:
* c-parser.cc (mark_exp_read_cond): New function.
(c_parser_unary_expression): Use mark_exp_read_cond.
(c_parser_postfix_expression_after_primary): Likewise.
* c-typeck.cc (build_unary_op): Remove dead code and
add checking assertion.
gcc/testuite/ChangeLog:
* gcc.dg/pr123569.c: New test.
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 6e8688d33ea..b578de7b15a 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -10656,6 +10656,26 @@ c_parser_cast_expression (c_parser *parser, struct
c_expr *after)
return c_parser_unary_expression (parser);
}
+
+/* Like mark_exp_read but skip marking VAR_DECLs and PARM_DECLs
+ depending on the warning mode. This helper function is
+ used in c_parser_unary_expression and
+ and c_parser_postfix_expression_after_primary for
+ pre/post-increment/decrement operations.
+ */
+
+static void
+mark_exp_read_cond (tree exp)
+{
+ if ((VAR_P (exp) || TREE_CODE (exp) == PARM_DECL)
+ && (VAR_P (exp) ? warn_unused_but_set_variable
+ : warn_unused_but_set_parameter) > 1)
+ return;
+
+ mark_exp_read (exp);
+}
+
+
/* Parse an unary expression (C90 6.3.3, C99 6.5.3, C11 6.5.3).
unary-expression:
@@ -10713,31 +10733,15 @@ c_parser_unary_expression (c_parser *parser)
c_parser_consume_token (parser);
exp_loc = c_parser_peek_token (parser)->location;
op = c_parser_cast_expression (parser, NULL);
- if ((VAR_P (op.value) || TREE_CODE (op.value) == PARM_DECL)
- && !DECL_READ_P (op.value)
- && (VAR_P (op.value) ? warn_unused_but_set_variable
- : warn_unused_but_set_parameter) > 1)
- {
- op = default_function_array_read_conversion (exp_loc, op);
- DECL_READ_P (op.value) = 0;
- }
- else
- op = default_function_array_read_conversion (exp_loc, op);
+ mark_exp_read_cond (op.value);
+ op = default_function_array_conversion (exp_loc, op);
return parser_build_unary_op (op_loc, PREINCREMENT_EXPR, op);
case CPP_MINUS_MINUS:
c_parser_consume_token (parser);
exp_loc = c_parser_peek_token (parser)->location;
op = c_parser_cast_expression (parser, NULL);
- if ((VAR_P (op.value) || TREE_CODE (op.value) == PARM_DECL)
- && !DECL_READ_P (op.value)
- && (VAR_P (op.value) ? warn_unused_but_set_variable
- : warn_unused_but_set_parameter) > 1)
- {
- op = default_function_array_read_conversion (exp_loc, op);
- DECL_READ_P (op.value) = 0;
- }
- else
- op = default_function_array_read_conversion (exp_loc, op);
+ mark_exp_read_cond (op.value);
+ op = default_function_array_conversion (exp_loc, op);
return parser_build_unary_op (op_loc, PREDECREMENT_EXPR, op);
case CPP_AND:
c_parser_consume_token (parser);
@@ -14207,17 +14211,8 @@ c_parser_postfix_expression_after_primary (c_parser
*parser,
start = expr.get_start ();
finish = c_parser_peek_token (parser)->get_finish ();
c_parser_consume_token (parser);
- if ((VAR_P (expr.value) || TREE_CODE (expr.value) == PARM_DECL)
- && !DECL_READ_P (expr.value)
- && (VAR_P (expr.value) ? warn_unused_but_set_variable
- : warn_unused_but_set_parameter) > 1
- && TREE_CODE (TREE_TYPE (expr.value)) != ARRAY_TYPE)
- {
- expr = default_function_array_read_conversion (expr_loc, expr);
- DECL_READ_P (expr.value) = 0;
- }
- else
- expr = default_function_array_read_conversion (expr_loc, expr);
+ mark_exp_read_cond (expr.value);
+ expr = default_function_array_conversion (expr_loc, expr);
expr.value = build_unary_op (op_loc, POSTINCREMENT_EXPR,
expr.value, false);
set_c_expr_source_range (&expr, start, finish);
@@ -14229,17 +14224,8 @@ c_parser_postfix_expression_after_primary (c_parser
*parser,
start = expr.get_start ();
finish = c_parser_peek_token (parser)->get_finish ();
c_parser_consume_token (parser);
- if ((VAR_P (expr.value) || TREE_CODE (expr.value) == PARM_DECL)
- && !DECL_READ_P (expr.value)
- && (VAR_P (expr.value) ? warn_unused_but_set_variable
- : warn_unused_but_set_parameter) > 1
- && TREE_CODE (TREE_TYPE (expr.value)) != ARRAY_TYPE)
- {
- expr = default_function_array_read_conversion (expr_loc, expr);
- DECL_READ_P (expr.value) = 0;
- }
- else
- expr = default_function_array_read_conversion (expr_loc, expr);
+ mark_exp_read_cond (expr.value);
+ expr = default_function_array_conversion (expr_loc, expr);
expr.value = build_unary_op (op_loc, POSTDECREMENT_EXPR,
expr.value, false);
set_c_expr_source_range (&expr, start, finish);
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 3606fc66abf..fade28a392b 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -5786,9 +5786,10 @@ build_unary_op (location_t location, enum tree_code
code, tree xarg,
tree ret = error_mark_node;
tree eptype = NULL_TREE;
const char *invalid_op_diag;
- bool int_operands;
- int_operands = EXPR_INT_CONST_OPERANDS (xarg);
+ gcc_checking_assert (!is_access_with_size_p (arg));
+
+ bool int_operands = EXPR_INT_CONST_OPERANDS (xarg);
if (int_operands)
arg = remove_c_maybe_const_expr (arg);
@@ -6250,10 +6251,7 @@ build_unary_op (location_t location, enum tree_code
code, tree xarg,
goto return_build_unary_op;
}
- /* Ordinary case; arg is a COMPONENT_REF or a decl, or a call to
- .ACCESS_WITH_SIZE. */
- if (is_access_with_size_p (arg))
- arg = TREE_OPERAND (TREE_OPERAND (CALL_EXPR_ARG (arg, 0), 0), 0);
+ /* Ordinary case; arg is a COMPONENT_REF or a decl. */
argtype = TREE_TYPE (arg);
diff --git a/gcc/testsuite/gcc.dg/pr123569.c b/gcc/testsuite/gcc.dg/pr123569.c
new file mode 100644
index 00000000000..508f9f1e7e2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr123569.c
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-options "-std=c99" } */
+
+struct buffer {
+ int len;
+ char * ptr __attribute((counted_by(len)));
+};
+int ltrim(struct buffer * const buf) {
+ while (buf->len > 0 && *buf->ptr == ' ') {
+ buf->len--;
+ buf->ptr++;
+ }
+ return buf->len;
+}
+int main() {
+ struct buffer buf = {.ptr = " 123", .len = 4};
+ int ret = ltrim(&buf);
+ if (3 != ret)
+ __builtin_abort();
+ return 0;
+}
+