Fix C handling of use of lvalues of incomplete types (PR c/36941, PR c/88827).
authorJoseph Myers <joseph@codesourcery.com>
Wed, 4 Dec 2019 23:26:10 +0000 (23:26 +0000)
committerJoseph Myers <jsm28@gcc.gnu.org>
Wed, 4 Dec 2019 23:26:10 +0000 (23:26 +0000)
Bug 88827 points out that GCC should not be rejecting C code that
dereferences a pointer to an incomplete type in the case that uses &*
to take the address of the resulting lvalue, because no constraint is
violated in that case (other than for C90 when the incomplete type is
unqualified void, which we already handle correctly) and as the lvalue
never gets converted to an rvalue there is no undefined behavior
either.

This means that the diagnostic for such a dereference is bogus and
should be removed; if the lvalue gets converted to an rvalue, there
should be an appropriate error later for the use of the incomplete
type.  In most cases, there is, but bug 36941 points out the lack of a
diagnostic when the incomplete (non-void) type gets cast to void
(where a diagnostic seems appropriate for this undefined behavior as a
matter of quality of implementation).

This patch removes the bogus diagnostic (and C_TYPE_ERROR_REPORTED
which was only used in the code that is removed - only that one, bogus
diagnostic had this duplicate suppression, not any of the other, more
legitimate diagnostics for use of incomplete types) and makes
convert_lvalue_to_rvalue call require_complete_type for arguments not
of void types, so that all relevant code paths (possibly except some
for ObjC) get incomplete types diagnosed.  It's possible that this
makes some other checks for incomplete types obsolete, but no attempt
is made to remove any such checks.

Bootstrapped with no regressions for x86_64-pc-linux-gnu.

PR c/36941
PR c/88827
gcc/c:
* c-typeck.c (convert_lvalue_to_rvalue): Call
require_complete_type for arguments not of void types.
(build_indirect_ref): Do not diagnose dereferencing pointers to
incomplete types.
* c-tree.h (C_TYPE_ERROR_REPORTED): Remove.

gcc/testsuite:
* gcc.dg/lvalue-9.c, gcc.dg/lvalue-10.c: New tests.
* gcc.dg/array-8.c, gcc.dg/enum-incomplete-1.c,
gcc.dg/enum-incomplete-3.c, gcc.dg/noncompile/incomplete-3.c,
gcc.dg/pr48552-1.c, gcc.dg/pr48552-2.c, gcc.dg/pr63543.c,
gcc.dg/pr69796.c: Update expected diagnostics.

From-SVN: r278976

14 files changed:
gcc/c/ChangeLog
gcc/c/c-tree.h
gcc/c/c-typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/array-8.c
gcc/testsuite/gcc.dg/enum-incomplete-1.c
gcc/testsuite/gcc.dg/enum-incomplete-3.c
gcc/testsuite/gcc.dg/lvalue-10.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/lvalue-9.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/noncompile/incomplete-3.c
gcc/testsuite/gcc.dg/pr48552-1.c
gcc/testsuite/gcc.dg/pr48552-2.c
gcc/testsuite/gcc.dg/pr63543.c
gcc/testsuite/gcc.dg/pr69796.c

index 3ea177ffbd6b855913f5024490d836857efdc8b2..f9c6293d9e5ec1f221be8e6d3bcc8484d6f5948b 100644 (file)
@@ -1,3 +1,13 @@
+2019-12-04  Joseph Myers  <joseph@codesourcery.com>
+
+       PR c/36941
+       PR c/88827
+       * c-typeck.c (convert_lvalue_to_rvalue): Call
+       require_complete_type for arguments not of void types.
+       (build_indirect_ref): Do not diagnose dereferencing pointers to
+       incomplete types.
+       * c-tree.h (C_TYPE_ERROR_REPORTED): Remove.
+
 2019-12-03  Joseph Myers  <joseph@codesourcery.com>
 
        PR c/88704
index cdfb90803462275bf652cba712c07504dc5ff982..ff2345dbe686da9d6227355c508569eafaf09d66 100644 (file)
@@ -55,9 +55,6 @@ along with GCC; see the file COPYING3.  If not see
    This is used for -Wc++-compat. */
 #define C_TYPE_DEFINED_IN_STRUCT(TYPE) TYPE_LANG_FLAG_2 (TYPE)
 
-/* Record whether an "incomplete type" error was given for the type.  */
-#define C_TYPE_ERROR_REPORTED(TYPE) TYPE_LANG_FLAG_3 (TYPE)
-
 /* Record whether a typedef for type `int' was actually `signed int'.  */
 #define C_TYPEDEF_EXPLICITLY_SIGNED(EXP) DECL_LANG_FLAG_1 (EXP)
 
index f9ab1e38b4268ccbeb950eca73bf626a9c791aa1..36aedc063d295c136c2b5fab6b268a909cb16685 100644 (file)
@@ -2054,6 +2054,8 @@ convert_lvalue_to_rvalue (location_t loc, struct c_expr exp,
     mark_exp_read (exp.value);
   if (convert_p)
     exp = default_function_array_conversion (loc, exp);
+  if (!VOID_TYPE_P (TREE_TYPE (exp.value)))
+    exp.value = require_complete_type (loc, exp.value);
   if (really_atomic_lvalue (exp.value))
     {
       vec<tree, va_gc> *params;
@@ -2550,16 +2552,6 @@ build_indirect_ref (location_t loc, tree ptr, ref_operator errstring)
 
          ref = build1 (INDIRECT_REF, t, pointer);
 
-         if (!COMPLETE_OR_VOID_TYPE_P (t) && TREE_CODE (t) != ARRAY_TYPE)
-           {
-             if (!C_TYPE_ERROR_REPORTED (TREE_TYPE (ptr)))
-               {
-                 error_at (loc, "dereferencing pointer to incomplete type "
-                           "%qT", t);
-                 C_TYPE_ERROR_REPORTED (TREE_TYPE (ptr)) = 1;
-               }
-             return error_mark_node;
-           }
          if (VOID_TYPE_P (t) && c_inhibit_evaluation_warnings == 0)
            warning_at (loc, 0, "dereferencing %<void *%> pointer");
 
index 7678625820f31afbd5cd0f174a96ae03754aa475..48a6d4501ad260b330f647ef111b05c8678c6900 100644 (file)
@@ -1,3 +1,13 @@
+2019-12-04  Joseph Myers  <joseph@codesourcery.com>
+
+       PR c/36941
+       PR c/88827
+       * gcc.dg/lvalue-9.c, gcc.dg/lvalue-10.c: New tests.
+       * gcc.dg/array-8.c, gcc.dg/enum-incomplete-1.c,
+       gcc.dg/enum-incomplete-3.c, gcc.dg/noncompile/incomplete-3.c,
+       gcc.dg/pr48552-1.c, gcc.dg/pr48552-2.c, gcc.dg/pr63543.c,
+       gcc.dg/pr69796.c: Update expected diagnostics.
+
 2019-12-04  Richard Sandiford  <richard.sandiford@arm.com>
 
        * gcc.target/aarch64/sve/acle/general/whilelt_5.c: New test.
index 644d84f14aab78394c8c997c84eab7ead2e43c9c..71c98038b86d6c3023223aa40b7ceb9b66fb3f63 100644 (file)
@@ -43,6 +43,5 @@ g (void)
   pv[0]; /* { dg-warning "dereferencing 'void \\*' pointer" } */
   0[pv]; /* { dg-warning "dereferencing 'void \\*' pointer" } */
   sip[0]; /* { dg-error "invalid use of undefined type 'struct si'" } */
-  /* { dg-error "dereferencing pointer to incomplete type" "incomplete" { target *-*-* } .-1 } */
   0[sip]; /* { dg-error "invalid use of undefined type 'struct si'" } */
 }
index 06c247c2e5120e5c96e3a8bf7d6399d8edd0fabd..2da3b58f54cfc6a8ba91d4648353f34682c19295 100644 (file)
@@ -13,14 +13,16 @@ f0 (int i)
 {
   ve; /* { dg-error "incomplete" } */
   vs; /* { dg-error "incomplete" } */
-  (void) ve;
-  (void) vs;
+  (void) ve; /* { dg-error "incomplete" } */
+  (void) vs; /* { dg-error "incomplete" } */
   (void) (i ? ve : ve); /* { dg-error "incomplete" } */
   (void) (i ? vs : vs); /* { dg-error "incomplete" } */
   (void) (ve = ve); /* { dg-error "incomplete" } */
   (void) (vs = vs); /* { dg-error "incomplete" } */
-  (void) ve, (void) ve;
-  (void) vs, (void) vs;
+  (void) ve, /* { dg-error "incomplete" } */
+    (void) ve; /* { dg-error "incomplete" } */
+  (void) vs, /* { dg-error "incomplete" } */
+    (void) vs; /* { dg-error "incomplete" } */
   p = &ve;
   p = &vs;
   (void) sizeof (ve); /* { dg-error "incomplete" } */
index db1138b56c61925ea2feb8b2e688638ce6c25758..12280db61fbd996ea1ea11e86b9cb43d8c889fec 100644 (file)
@@ -4,17 +4,17 @@
 
 enum E e; /* { dg-error "storage size" } */
 
-void bar (int [e]); /* { dg-error "size of unnamed array has incomplete type" } */
-void bar2 (int [][e]); /* { dg-error "size of unnamed array has incomplete type" } */
+void bar (int [e]); /* { dg-error "has an incomplete type" } */
+void bar2 (int [][e]); /* { dg-error "has an incomplete type" } */
 
 void
 foo (void)
 {
-  int a1[e]; /* { dg-error "size of array .a1. has incomplete type" } */
-  int a2[e][3]; /* { dg-error "size of array .a2. has incomplete type" } */
+  int a1[e]; /* { dg-error "has an incomplete type" } */
+  int a2[e][3]; /* { dg-error "has an incomplete type" } */
 
   struct S
   {
-    int a3[e]; /* { dg-error "size of array .a3. has incomplete type" } */
+    int a3[e]; /* { dg-error "has an incomplete type" } */
   };
 }
diff --git a/gcc/testsuite/gcc.dg/lvalue-10.c b/gcc/testsuite/gcc.dg/lvalue-10.c
new file mode 100644 (file)
index 0000000..cc5f37b
--- /dev/null
@@ -0,0 +1,22 @@
+/* Test handling of lvalues of incomplete types.  Bugs 36941, 88647
+   (invalid), 88827.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -pedantic-errors" } */
+
+struct S;
+
+extern struct S var;
+extern struct S *vp;
+
+void
+f8 (void)
+{
+  /* These are valid because there is no constraint violation and the
+     result of '*' is never converted from an lvalue to an rvalue
+     (which would yield undefined behavior).  */
+  &var;
+  &*vp;
+  &(var);
+  &(*vp);
+  &*&*vp;
+}
diff --git a/gcc/testsuite/gcc.dg/lvalue-9.c b/gcc/testsuite/gcc.dg/lvalue-9.c
new file mode 100644 (file)
index 0000000..382b3ff
--- /dev/null
@@ -0,0 +1,77 @@
+/* Test handling of lvalues of incomplete types.  Bugs 36941, 88647
+   (invalid), 88827.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -pedantic-errors" } */
+
+struct S;
+
+extern struct S var;
+extern struct S *vp;
+extern int i;
+
+void
+f1 (void)
+{
+  var; /* { dg-error "has an incomplete type" } */
+  var, (void) 0; /* { dg-error "has an incomplete type" } */
+  (i
+   ? var /* { dg-error "has an incomplete type" } */
+   : var); /* { dg-error "has an incomplete type" } */
+}
+
+void
+f2 (void)
+{
+  (void) var; /* { dg-error "has an incomplete type" } */
+  (void) (var, (void) 0); /* { dg-error "has an incomplete type" } */
+  (void) (i
+         ? var /* { dg-error "has an incomplete type" } */
+         : var); /* { dg-error "has an incomplete type" } */
+}
+
+void
+f3 (void)
+{
+  (const void) var; /* { dg-error "has an incomplete type" } */
+  (const void) (var, (void) 0); /* { dg-error "has an incomplete type" } */
+  (const void) (i
+               ? var /* { dg-error "has an incomplete type" } */
+               : var); /* { dg-error "has an incomplete type" } */
+}
+
+void
+f4 (void)
+{
+  *vp; /* { dg-error "invalid use of undefined type" } */
+  *vp, (void) 0; /* { dg-error "invalid use of undefined type" } */
+  (i
+   ? *vp /* { dg-error "invalid use of undefined type" } */
+   : *vp); /* { dg-error "invalid use of undefined type" } */
+}
+
+void
+f5 (void)
+{
+  (void) *vp; /* { dg-error "invalid use of undefined type" } */
+  (void) (*vp, (void) 0); /* { dg-error "invalid use of undefined type" } */
+  (void) (i
+         ? *vp /* { dg-error "invalid use of undefined type" } */
+         : *vp); /* { dg-error "invalid use of undefined type" } */
+}
+
+void
+f6 (void)
+{
+  (const void) *vp; /* { dg-error "invalid use of undefined type" } */
+  (const void) (*vp, (void) 0); /* { dg-error "invalid use of undefined type" } */
+  (const void) (i
+               ? *vp /* { dg-error "invalid use of undefined type" } */
+               : *vp); /* { dg-error "invalid use of undefined type" } */
+}
+
+void
+f7 (void)
+{
+  /* This is invalid because of the constraints on [].  */
+  &vp[0]; /* { dg-error "invalid use of undefined type" } */
+}
index 735ef465b38a5265fa51a5c0bcd270a59ec903b5..0618b4d81705a75f73ac1b125cce53b102c87502 100644 (file)
@@ -5,5 +5,5 @@ int foo (void)
 {
   b_t d;
   struct b_t *c = &d;  /* { dg-warning "incompatible pointer type" } */
-  c->a;                        /* { dg-error "incomplete type" } */
+  c->a;                        /* { dg-error "invalid use of undefined type" } */
 }
index 70d3483d80cd869ee74bf3c54df71d6554d2ca18..11ee401e0307400f7489574ddf0f287d9e4eedb7 100644 (file)
@@ -43,11 +43,12 @@ f6 (void *x)
 void
 f7 (struct S *x)
 {
-  __asm volatile ("" : : "r" (*x));    /* { dg-error "dereferencing pointer to incomplete type" } */
+  __asm volatile ("" : : "r" (*x));    /* { dg-error "invalid use of undefined type" } */
 }
 
 void
 f8 (struct S *x)
 {
-  __asm volatile ("" : "=r" (*x));     /* { dg-error "invalid lvalue in 'asm' output 0" } */
+  __asm volatile ("" : "=r" (*x));     /* { dg-error "impossible constraint in 'asm'" } */
+  /* { dg-error "non-memory output 0 must stay in memory" "memory" { target *-*-* } .-1 } */
 }
index ce6bece3f964398935a753ab4614ff6b1893347b..2d2a00c43b70456948843b8a2caca670d3739e3f 100644 (file)
@@ -43,11 +43,12 @@ f6 (void *x)
 void
 f7 (struct S *x)
 {
-  __asm ("" : : "r" (*x));     /* { dg-error "dereferencing pointer to incomplete type" } */
+  __asm ("" : : "r" (*x));     /* { dg-error "invalid use of undefined type" } */
 }
 
 void
 f8 (struct S *x)
 {
-  __asm ("" : "=r" (*x));      /* { dg-error "invalid lvalue in 'asm' output 0" } */
+  __asm ("" : "=r" (*x));      /* { dg-error "impossible constraint in 'asm'" } */
+  /* { dg-error "non-memory output 0 must stay in memory" "memory" { target *-*-* } .-1 } */
 }
index 215b62ed911f8c1cf8137b1e26d9f2ec27227241..d85e10d2021eb4d8a88503a0b50d4324e079ff65 100644 (file)
@@ -7,15 +7,15 @@ union U;
 int
 f1 (struct S *s)
 {
-  return s->a /* { dg-error "dereferencing pointer to incomplete type .struct S." } */
-        + s->b
-        + s->c;
+  return s->a /* { dg-error "invalid use of undefined type .struct S." } */
+        + s->b /* { dg-error "invalid use of undefined type .struct S." } */
+        + s->c; /* { dg-error "invalid use of undefined type .struct S." } */
 }
 
 int
 f2 (union U *u)
 {
-  return u->a /* { dg-error "dereferencing pointer to incomplete type .union U." } */
-        + u->a
-        + u->a;
+  return u->a /* { dg-error "invalid use of undefined type .union U." } */
+        + u->a /* { dg-error "invalid use of undefined type .union U." } */
+        + u->a; /* { dg-error "invalid use of undefined type .union U." } */
 }
index ebf34aaa2164e53d487683c081f698c9ba8e2575..4b725a50767181d5a902fb00de1e82083f701cef 100644 (file)
@@ -6,5 +6,5 @@ struct S s;     /* { dg-error "storage size of 's' isn't known" } */
 void
 foo ()
 {
-  s a; /* { dg-error "expression statement has incomplete type|expected" } */
+  s a; /* { dg-error "has an incomplete type|expected" } */
 }