We did not propagate C_TYPE_VARIABLY_MODIFIED to pointers in all cases. I added this directly in two places, but maybe we should check all cases of build_pointer_type or integrate this into c_build_pointer_type and use this everywhere (but I do not fully understand the pointer mode logic there).
Bootstrapped and regession tested on x86_64. c: Fix for some variably modified types not being recognized [PR114831] We did not evaluate expressions with variably modified types correctly in typeof and did not produce warnings when jumping over declarations using typeof. After addressof or array-to-pointer decay we construct new pointer types that have to be marked variably modified if the pointer target is variably modified. 2024-05-18 Martin Uecker <uec...@tugraz.at> PR c/114831 gcc/c/ * c-typeck.cc (array_to_pointer_conversion, build_unary_op): Propagate flag to pointer target. gcc/testsuite/ * gcc.dg/pr114831-1.c: New test. * gcc.dg/pr114831-2.c: New test. * gcc.dg/gnu23-varmod-1.c: New test. * gcc.dg/gnu23-varmod-2.c: New test. diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 7ecca9f58c6..2d092357e0f 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -1891,8 +1891,12 @@ array_to_pointer_conversion (location_t loc, tree exp) copy_warning (exp, orig_exp); + bool varmod = C_TYPE_VARIABLY_MODIFIED (restype); + ptrtype = build_pointer_type (restype); + C_TYPE_VARIABLY_MODIFIED (ptrtype) = varmod; + if (INDIRECT_REF_P (exp)) return convert (ptrtype, TREE_OPERAND (exp, 0)); @@ -4630,6 +4634,7 @@ build_unary_op (location_t location, enum tree_code code, tree xarg, tree eptype = NULL_TREE; const char *invalid_op_diag; bool int_operands; + bool varmod; int_operands = EXPR_INT_CONST_OPERANDS (xarg); if (int_operands) @@ -5113,8 +5118,12 @@ build_unary_op (location_t location, enum tree_code code, tree xarg, gcc_assert (TREE_CODE (arg) != COMPONENT_REF || !DECL_C_BIT_FIELD (TREE_OPERAND (arg, 1))); + varmod = C_TYPE_VARIABLY_MODIFIED (argtype); + argtype = build_pointer_type (argtype); + C_TYPE_VARIABLY_MODIFIED (argtype) = varmod; + /* ??? Cope with user tricks that amount to offsetof. Delete this when we have proper support for integer constant expressions. */ val = get_base_address (arg); diff --git a/gcc/testsuite/gcc.dg/gnu23-varmod-1.c b/gcc/testsuite/gcc.dg/gnu23-varmod-1.c new file mode 100644 index 00000000000..add10d13573 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gnu23-varmod-1.c @@ -0,0 +1,12 @@ +/* { dg-do compile } + * { dg-options "-std=gnu23" } */ + +int foo(int n) +{ + int (*a(void))[n] { return 0; }; + goto err; /* { dg-error "jump into scope" "variably modified" } */ + typeof((n++,a)) b2; +err: + return n; +} + diff --git a/gcc/testsuite/gcc.dg/gnu23-varmod-2.c b/gcc/testsuite/gcc.dg/gnu23-varmod-2.c new file mode 100644 index 00000000000..c36af1d1647 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gnu23-varmod-2.c @@ -0,0 +1,16 @@ +/* { dg-do run } + * { dg-options "-std=gnu23" } */ + +int foo(int n) +{ + int (*a(void))[n] { return 0; }; + typeof((n++,a)) b2; + return n; +} + +int main() +{ + if (2 != foo(1)) + __builtin_abort(); +} + diff --git a/gcc/testsuite/gcc.dg/pr114831-1.c b/gcc/testsuite/gcc.dg/pr114831-1.c new file mode 100644 index 00000000000..ed30a494b3c --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr114831-1.c @@ -0,0 +1,27 @@ +/* { dg-do compile } + * { dg-options "-std=c23" } */ + +void f(int n) +{ + int a[n]; + goto foo; /* { dg-error "jump into scope" "variably modified" } */ + typeof(a) b1; +foo: +} + +void g(int n) +{ + int a2[1][n]; + goto foo; /* { dg-error "jump into scope" "variably modified" } */ + typeof((n++,a2)) b2; +foo: +} + +void h(int n) +{ + int a[n]; + typeof(a) b1; + goto foo; /* { dg-error "jump into scope" "variably modified" } */ + typeof(&b1) b; +foo: +} diff --git a/gcc/testsuite/gcc.dg/pr114831-2.c b/gcc/testsuite/gcc.dg/pr114831-2.c new file mode 100644 index 00000000000..ecfd87988c2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr114831-2.c @@ -0,0 +1,16 @@ +/* { dg-do run } + * { dg-options "-std=c23" } */ + +int foo(int n) +{ + int a[1][n]; + typeof((n++,a)) b2; + return n; +} + +int main() +{ + if (2 != foo(1)) + __builtin_abort(); +} +