From: Joseph Myers Date: Sat, 20 Sep 2025 00:24:26 +0000 (+0000) Subject: c: Implement C2y N3481 constraint against lvalue conversion with incomplete type X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=3eca9b5119f235666a2d97cb77a6cddc567bbe8b;p=thirdparty%2Fgcc.git c: Implement C2y N3481 constraint against lvalue conversion with incomplete type C2y replaces undefined behavior for lvalue conversion of an lvalue with incomplete, non-array type with a constraint violation. Implement this in GCC, which means disallowing lvalue conversion of qualified or atomic void for C2y. (Unqualified, non-atomic void is excluded from the definition of "lvalue".) I'm not convinced that the resolution of C90 DR#106 (which said that certain cases with qualified void were valid) was really justified even based on the wording of C90; nevertheless, this patch takes the conservative approach of only disallowing qualified void here for C2y. The test for this change showed that attempting to access an _Atomic void object produced an ICE-after-error attempting the atomic load logic for such a type. require_complete_type returning error_mark_node prevents this ICE from occurring any more in C2y mode; to avoid it in older modes, a check of COMPLETE_TYPE_P is added to really_atomic_lvalue. I didn't find any existing bug report in Bugzilla for this issue. Bootstrapped with no regressions for x86_64-pc-linux-gnu. gcc/c/ * c-typeck.cc (really_atomic_lvalue): Return false for incomplete types. (convert_lvalue_to_rvalue): Call require_complete_type for qualified void for C2y. gcc/testsuite/ * gcc.dg/c11-atomic-6.c, gcc.dg/c23-incomplete-1.c, gcc.dg/c2y-incomplete-3.c: New tests. --- diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 1f04a4d7f4f..624e7a3fa35 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -2512,6 +2512,8 @@ really_atomic_lvalue (tree expr) return false; if (!TYPE_ATOMIC (TREE_TYPE (expr))) return false; + if (!COMPLETE_TYPE_P (TREE_TYPE (expr))) + return false; if (!lvalue_p (expr)) return false; @@ -2607,7 +2609,9 @@ convert_lvalue_to_rvalue (location_t loc, struct c_expr exp, if (convert_p) exp = default_function_array_conversion (loc, exp); - if (!VOID_TYPE_P (TREE_TYPE (exp.value))) + if (!VOID_TYPE_P (TREE_TYPE (exp.value)) + || (flag_isoc2y + && TYPE_QUALS (TREE_TYPE (exp.value)) != TYPE_UNQUALIFIED)) exp.value = require_complete_type (loc, exp.value); if (for_init || !RECORD_OR_UNION_TYPE_P (TREE_TYPE (exp.value))) { diff --git a/gcc/testsuite/gcc.dg/c11-atomic-6.c b/gcc/testsuite/gcc.dg/c11-atomic-6.c new file mode 100644 index 00000000000..4bb771fe596 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c11-atomic-6.c @@ -0,0 +1,13 @@ +/* Test ICE accessing _Atomic void object. */ +/* { dg-do compile } */ +/* { dg-options "-std=c11" } */ + +extern _Atomic void x; + +void +f (void) +{ + /* This has undefined behavior (lvalue conversion on an incomplete type) but + should not produce an ICE. */ + x; +} diff --git a/gcc/testsuite/gcc.dg/c23-incomplete-1.c b/gcc/testsuite/gcc.dg/c23-incomplete-1.c new file mode 100644 index 00000000000..c80361a8347 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-incomplete-1.c @@ -0,0 +1,36 @@ +/* Test C2y constraint against lvalue conversion of lvalues with incomplete + type: not applied in C23 mode. Although it is not clear that these + constructs are valid in C23, we allow certain cases of qualified void + there. */ +/* { dg-do compile } */ +/* { dg-options "-std=c23 -pedantic-errors" } */ + +struct s; +union u; + +extern struct s vs, *ps; +extern _Atomic struct s vas, *pas; +extern union u vu, *pu; +extern _Atomic union u vau, *pau; + +extern const void cv, *pcv; +extern _Atomic void av, *pav; + +void +f () +{ + vs; /* { dg-error "incomplete type" } */ + *ps; /* { dg-error "invalid use of undefined type" } */ + vas; /* { dg-error "incomplete type" } */ + *pas; /* { dg-error "invalid use of undefined type" } */ + vu; /* { dg-error "incomplete type" } */ + *pu; /* { dg-error "invalid use of undefined type" } */ + vau; /* { dg-error "incomplete type" } */ + *pau; /* { dg-error "invalid use of undefined type" } */ + cv; + *pcv; + /* { dg-warning "dereferencing" "dereferencing" { target *-*-* } .-1 } */ + av; + *pav; + /* { dg-warning "dereferencing" "dereferencing" { target *-*-* } .-1 } */ +} diff --git a/gcc/testsuite/gcc.dg/c2y-incomplete-3.c b/gcc/testsuite/gcc.dg/c2y-incomplete-3.c new file mode 100644 index 00000000000..0a18fdadf81 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2y-incomplete-3.c @@ -0,0 +1,34 @@ +/* Test C2y constraint against lvalue conversion of lvalues with incomplete + type. */ +/* { dg-do compile } */ +/* { dg-options "-std=c2y -pedantic-errors" } */ + +struct s; +union u; + +extern struct s vs, *ps; +extern _Atomic struct s vas, *pas; +extern union u vu, *pu; +extern _Atomic union u vau, *pau; + +extern const void cv, *pcv; +extern _Atomic void av, *pav; + +void +f () +{ + vs; /* { dg-error "incomplete type" } */ + *ps; /* { dg-error "invalid use of undefined type" } */ + vas; /* { dg-error "incomplete type" } */ + *pas; /* { dg-error "invalid use of undefined type" } */ + vu; /* { dg-error "incomplete type" } */ + *pu; /* { dg-error "invalid use of undefined type" } */ + vau; /* { dg-error "incomplete type" } */ + *pau; /* { dg-error "invalid use of undefined type" } */ + cv; /* { dg-error "incomplete type" } */ + *pcv; /* { dg-error "invalid use of void expression" } */ + /* { dg-warning "dereferencing" "dereferencing" { target *-*-* } .-1 } */ + av; /* { dg-error "incomplete type" } */ + *pav; /* { dg-error "invalid use of void expression" } */ + /* { dg-warning "dereferencing" "dereferencing" { target *-*-* } .-1 } */ +}