aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Myers <josmyers@redhat.com>2025-09-20 00:24:26 +0000
committerJoseph Myers <josmyers@redhat.com>2025-09-20 00:24:26 +0000
commit3eca9b5119f235666a2d97cb77a6cddc567bbe8b (patch)
tree1de98b944bf7a5802f9efb96c4cc73330aab441e
parentdcc231417fcb24f90ad2563c47edee04326426a1 (diff)
downloadgcc-3eca9b5119f235666a2d97cb77a6cddc567bbe8b.zip
gcc-3eca9b5119f235666a2d97cb77a6cddc567bbe8b.tar.gz
gcc-3eca9b5119f235666a2d97cb77a6cddc567bbe8b.tar.bz2
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.
-rw-r--r--gcc/c/c-typeck.cc6
-rw-r--r--gcc/testsuite/gcc.dg/c11-atomic-6.c13
-rw-r--r--gcc/testsuite/gcc.dg/c23-incomplete-1.c36
-rw-r--r--gcc/testsuite/gcc.dg/c2y-incomplete-3.c34
4 files changed, 88 insertions, 1 deletions
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 1f04a4d..624e7a3 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 0000000..4bb771f
--- /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 0000000..c80361a
--- /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 0000000..0a18fda
--- /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 } */
+}