This patch fixes the ICE according to comment #10 in the PR.
Bootstrapped and regression tested on x86_64.
When array type is passed to va_arg, this is undefined behavior.
Emit a warning and insert a run-time trap after evaluating side effects,
but return the correct type for sizeof / typeof. For C90 a VLA is an
error.
PR c/97986
gcc/c/ChangeLog:
* c-parser.cc (c_parser_postfix_expression): Adapt.
* c-typeck.cc (c_build_va_arg): Handle UB.
gcc/testsuite/ChangeLog:
* gcc.dg/pr97986-1.c: New test.
* gcc.dg/pr97986-2.c: New test.
---
gcc/c/c-parser.cc | 10 ++--------
gcc/c/c-tree.h | 2 +-
gcc/c/c-typeck.cc | 31 +++++++++++++++++++++++++++++--
gcc/testsuite/gcc.dg/pr97986-1.c | 28 ++++++++++++++++++++++++++++
gcc/testsuite/gcc.dg/pr97986-2.c | 15 +++++++++++++++
5 files changed, 75 insertions(+), 11 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/pr97986-1.c
create mode 100644 gcc/testsuite/gcc.dg/pr97986-2.c
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 0cf3f92a72c..a559a4e6a06 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -11793,15 +11793,9 @@ c_parser_postfix_expression (c_parser *parser)
else
{
tree type_expr = NULL_TREE;
+ tree type = groktypename (t1, &type_expr, NULL);
expr.value = c_build_va_arg (start_loc, e1.value, loc,
- groktypename (t1, &type_expr,
NULL));
- if (type_expr)
- {
- expr.value = build2 (C_MAYBE_CONST_EXPR,
- TREE_TYPE (expr.value), type_expr,
- expr.value);
- C_MAYBE_CONST_EXPR_NON_CONST (expr.value) = true;
- }
+ type, type_expr);
set_c_expr_source_range (&expr, start_loc, end_loc);
}
}
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index f367cda35d7..ff63d69e85d 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -917,7 +917,7 @@ extern tree c_omp_finish_mapper_clauses (tree);
extern tree c_omp_mapper_lookup (tree, tree);
extern tree c_omp_extract_mapper_directive (tree);
extern tree c_omp_map_array_section (location_t, tree);
-extern tree c_build_va_arg (location_t, tree, location_t, tree);
+extern tree c_build_va_arg (location_t, tree, location_t, tree, tree);
extern tree c_finish_transaction (location_t, tree, int);
extern bool c_tree_equal (tree, tree);
extern tree c_build_function_call_vec (location_t, const vec<location_t>&,
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index bc0fb6b59e5..b965f9ee416 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -18435,7 +18435,8 @@ c_build_qualified_type (tree type, int type_quals, tree
orig_qual_type,
/* Build a VA_ARG_EXPR for the C parser. */
tree
-c_build_va_arg (location_t loc1, tree expr, location_t loc2, tree type)
+c_build_va_arg (location_t loc1, tree expr, location_t loc2, tree type,
+ tree type_expr)
{
if (error_operand_p (type))
return error_mark_node;
@@ -18459,10 +18460,36 @@ c_build_va_arg (location_t loc1, tree expr,
location_t loc2, tree type)
type);
return error_mark_node;
}
+ else if (TREE_CODE (type) == ARRAY_TYPE && C_TYPE_VARIABLE_SIZE (type)
+ && !flag_isoc99)
+ {
+ error_at (loc2, "second argument to %<va_arg%> is an array type %qT",
+ type);
+ return error_mark_node;
+ }
else if (warn_cxx_compat && TREE_CODE (type) == ENUMERAL_TYPE)
warning_at (loc2, OPT_Wc___compat,
"C++ requires promoted type, not enum type, in %<va_arg%>");
- return build_va_arg (loc2, expr, type);
+
+ if (flag_isoc99 && TREE_CODE (type) == ARRAY_TYPE)
+ {
+ warning_at (loc2, 0, "second argument to %<va_arg%> is an array type
%qT",
+ type);
+ /* We create a trap but evaluate side effects first. */
+ tree trapfn = builtin_decl_explicit (BUILT_IN_TRAP);
+ trapfn = build_call_expr_loc (loc2, trapfn, 0);
+ tree e2 = build2 (COMPOUND_EXPR, void_type_node, expr, trapfn);
+ /* Return a compound literal of the right type. */
+ tree e1 = build_compound_literal (loc2, type, NULL, true, 0, NULL);
+ expr = build2 (COMPOUND_EXPR, type, e2, e1);
+ }
+ else
+ expr = build_va_arg (loc2, expr, type);
+
+ if (type_expr)
+ expr = build2 (COMPOUND_EXPR, TREE_TYPE (expr), type_expr, expr);
+
+ return expr;
}
/* Return truthvalue of whether T1 is the same tree structure as T2.
diff --git a/gcc/testsuite/gcc.dg/pr97986-1.c b/gcc/testsuite/gcc.dg/pr97986-1.c
new file mode 100644
index 00000000000..3824fb4e143
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr97986-1.c
@@ -0,0 +1,28 @@
+/* { dg-do run } */
+/* { dg-options "-std=gnu23" } */
+
+#include <stdarg.h>
+
+int f(int n, ...)
+{
+ __label__ b, d;
+ va_list ap;
+ va_start(ap, n);
+ _Static_assert(5 == sizeof(va_arg(ap, char[5]))); /* { dg-warning
"array type" } */
+ void g(void) { n++; goto b; }
+ int *a = va_arg((g(), ap), int[n]); /* { dg-warning "array type" }
*/
+b:
+ void h(void) { n++; goto d; }
+ typeof(va_arg(ap, int[(h(), n)])) c; /* { dg-warning "array type" }
*/
+d:
+ return n;
+}
+
+int main()
+{
+ if (9 != f(7))
+ __builtin_abort();
+ return 0;
+}
+
+
diff --git a/gcc/testsuite/gcc.dg/pr97986-2.c b/gcc/testsuite/gcc.dg/pr97986-2.c
new file mode 100644
index 00000000000..fc23a57907c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr97986-2.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c90" } */
+
+#include <stdarg.h>
+
+
+int f(int n, ...)
+{
+ va_list ap;
+ va_start(ap, n);
+ _Static_assert(5 == sizeof(va_arg(ap, char[5])));
+ va_arg(ap, int[n]); /* { dg-error "array type" } */
+ int * a = va_arg(ap, int[3]); /* { dg-error "invalid use of
non-lvalue array" } */
+}
+
--
2.47.3