]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Correct treatment of qualifiers for pointers to arrays for C2X [PR98397]
authorMartin Uecker <muecker@gwdg.de>
Sun, 22 Aug 2021 21:47:58 +0000 (23:47 +0200)
committerMartin Uecker <muecker@gwdg.de>
Sun, 22 Aug 2021 22:15:17 +0000 (00:15 +0200)
2021-08-22  Martin Uecker  <muecker@gwdg.de>

gcc/c/
PR c/98397
* c-typeck.c (comp_target_types): Change pedwarn to pedwarn_c11
for pointers to arrays with qualifiers.
(build_conditional_expr): For C23 don't lose qualifiers for pointers
to arrays when the other pointer is a void pointer. Update warnings.
(convert_for_assignment): Update warnings for C2X when converting from
void* with qualifiers to a pointer to array with the same qualifiers.

gcc/testsuite/
PR c/98397
* gcc.dg/c11-qual-1.c: New test.
* gcc.dg/c2x-qual-1.c: New test.
* gcc.dg/c2x-qual-2.c: New test.
* gcc.dg/c2x-qual-3.c: New test.
* gcc.dg/c2x-qual-4.c: New test.
* gcc.dg/c2x-qual-5.c: New test.
* gcc.dg/c2x-qual-6.c: New test.
* gcc.dg/c2x-qual-7.c: New test.
* gcc.dg/pointer-array-quals-1.c: Remove unnecessary flag.
* gcc.dg/pointer-array-quals-2.c: Remove unnecessary flag.

gcc/c/c-typeck.c
gcc/testsuite/gcc.dg/c11-qual-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c2x-qual-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c2x-qual-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c2x-qual-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c2x-qual-4.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c2x-qual-5.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c2x-qual-6.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c2x-qual-7.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pointer-array-quals-1.c
gcc/testsuite/gcc.dg/pointer-array-quals-2.c

index 0c07af61f24f015f17d055ef398445333c9d8f85..d9f26d67bd33fad5e68e48a04989deac5ecd4658 100644 (file)
@@ -1328,8 +1328,8 @@ comp_target_types (location_t location, tree ttl, tree ttr)
   val = comptypes_check_enum_int (mvl, mvr, &enum_and_int_p);
 
   if (val == 1 && val_ped != 1)
-    pedwarn (location, OPT_Wpedantic, "pointers to arrays with different qualifiers "
-                                      "are incompatible in ISO C");
+    pedwarn_c11 (location, OPT_Wpedantic, "invalid use of pointers to arrays with different qualifiers "
+                                         "in ISO C before C2X");
 
   if (val == 2)
     pedwarn (location, OPT_Wpedantic, "types are not quite compatible");
@@ -5406,39 +5406,41 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp,
                    "used in conditional expression");
          return error_mark_node;
        }
-      else if (VOID_TYPE_P (TREE_TYPE (type1))
-              && !TYPE_ATOMIC (TREE_TYPE (type1)))
-       {
-         if ((TREE_CODE (TREE_TYPE (type2)) == ARRAY_TYPE)
-             && (TYPE_QUALS (strip_array_types (TREE_TYPE (type2)))
-                 & ~TYPE_QUALS (TREE_TYPE (type1))))
-           warning_at (colon_loc, OPT_Wdiscarded_array_qualifiers,
-                       "pointer to array loses qualifier "
-                       "in conditional expression");
-
-         if (TREE_CODE (TREE_TYPE (type2)) == FUNCTION_TYPE)
+      else if ((VOID_TYPE_P (TREE_TYPE (type1))
+               && !TYPE_ATOMIC (TREE_TYPE (type1)))
+              || (VOID_TYPE_P (TREE_TYPE (type2))
+                  && !TYPE_ATOMIC (TREE_TYPE (type2))))
+       {
+         tree t1 = TREE_TYPE (type1);
+         tree t2 = TREE_TYPE (type2);
+         if (!(VOID_TYPE_P (t1)
+               && !TYPE_ATOMIC (t1)))
+          {
+            /* roles are swapped */
+            t1 = t2;
+            t2 = TREE_TYPE (type1);
+          }
+         tree t2_stripped = strip_array_types (t2);
+         if ((TREE_CODE (t2) == ARRAY_TYPE)
+             && (TYPE_QUALS (t2_stripped) & ~TYPE_QUALS (t1)))
+           {
+             if (!flag_isoc2x)
+               warning_at (colon_loc, OPT_Wdiscarded_array_qualifiers,
+                           "pointer to array loses qualifier "
+                           "in conditional expression");
+             else if (warn_c11_c2x_compat > 0)
+               warning_at (colon_loc, OPT_Wc11_c2x_compat,
+                           "pointer to array loses qualifier "
+                           "in conditional expression in ISO C before C2X");
+           }
+         if (TREE_CODE (t2) == FUNCTION_TYPE)
            pedwarn (colon_loc, OPT_Wpedantic,
                     "ISO C forbids conditional expr between "
                     "%<void *%> and function pointer");
-         result_type = build_pointer_type (qualify_type (TREE_TYPE (type1),
-                                                         TREE_TYPE (type2)));
-       }
-      else if (VOID_TYPE_P (TREE_TYPE (type2))
-              && !TYPE_ATOMIC (TREE_TYPE (type2)))
-       {
-         if ((TREE_CODE (TREE_TYPE (type1)) == ARRAY_TYPE)
-             && (TYPE_QUALS (strip_array_types (TREE_TYPE (type1)))
-                 & ~TYPE_QUALS (TREE_TYPE (type2))))
-           warning_at (colon_loc, OPT_Wdiscarded_array_qualifiers,
-                       "pointer to array loses qualifier "
-                       "in conditional expression");
-
-         if (TREE_CODE (TREE_TYPE (type1)) == FUNCTION_TYPE)
-           pedwarn (colon_loc, OPT_Wpedantic,
-                    "ISO C forbids conditional expr between "
-                    "%<void *%> and function pointer");
-         result_type = build_pointer_type (qualify_type (TREE_TYPE (type2),
-                                                         TREE_TYPE (type1)));
+         /* for array, use qualifiers of element type */
+         if (flag_isoc2x)
+           t2 = t2_stripped;
+         result_type = build_pointer_type (qualify_type (t1, t2));
        }
       /* Objective-C pointer comparisons are a bit more lenient.  */
       else if (objc_have_common_type (type1, type2, -3, NULL_TREE))
@@ -6797,27 +6799,40 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
 
   /* This macro is used to emit diagnostics to ensure that all format
      strings are complete sentences, visible to gettext and checked at
-     compile time.  It is the same as PEDWARN_FOR_ASSIGNMENT but with an
-     extra parameter to enumerate qualifiers.  */
-#define PEDWARN_FOR_QUALIFIERS(LOCATION, PLOC, OPT, AR, AS, IN, RE, QUALS) \
+     compile time.  It can be called with 'pedwarn' or 'warning_at'.  */
+#define WARNING_FOR_QUALIFIERS(PEDWARN, LOCATION, PLOC, OPT, AR, AS, IN, RE, QUALS) \
   do {                                                                   \
     switch (errtype)                                                     \
       {                                                                  \
       case ic_argpass:                                                   \
-       {                                                               \
-       auto_diagnostic_group d;                                                \
-       if (pedwarn (PLOC, OPT, AR, parmnum, rname, QUALS))             \
-         inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype);     \
-       }                                                               \
+       {                                                                \
+         auto_diagnostic_group d;                                       \
+         if (PEDWARN) {                                                 \
+           if (pedwarn (PLOC, OPT, AR, parmnum, rname, QUALS))          \
+             inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype);  \
+         } else {                                                       \
+           if (warning_at (PLOC, OPT, AR, parmnum, rname, QUALS))       \
+             inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype);  \
+         }                                                              \
+       }                                                                \
         break;                                                           \
       case ic_assign:                                                    \
-        pedwarn (LOCATION, OPT, AS, QUALS);                             \
+       if (PEDWARN)                                                     \
+         pedwarn (LOCATION, OPT, AS, QUALS);                            \
+       else                                                             \
+         warning_at (LOCATION, OPT, AS, QUALS);                         \
         break;                                                           \
       case ic_init:                                                      \
-        pedwarn (LOCATION, OPT, IN, QUALS);                             \
+       if (PEDWARN)                                                     \
+         pedwarn (LOCATION, OPT, IN, QUALS);                            \
+       else                                                             \
+         warning_at (LOCATION, OPT, IN, QUALS);                         \
         break;                                                           \
       case ic_return:                                                    \
-        pedwarn (LOCATION, OPT, RE, QUALS);                             \
+       if (PEDWARN)                                                     \
+         pedwarn (LOCATION, OPT, RE, QUALS);                            \
+       else                                                             \
+         warning_at (LOCATION, OPT, RE, QUALS);                         \
         break;                                                           \
       default:                                                           \
         gcc_unreachable ();                                              \
@@ -6826,32 +6841,11 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
 
   /* This macro is used to emit diagnostics to ensure that all format
      strings are complete sentences, visible to gettext and checked at
-     compile time.  It is the same as PEDWARN_FOR_QUALIFIERS but uses
-     warning_at instead of pedwarn.  */
-#define WARNING_FOR_QUALIFIERS(LOCATION, PLOC, OPT, AR, AS, IN, RE, QUALS) \
-  do {                                                                   \
-    switch (errtype)                                                     \
-      {                                                                  \
-      case ic_argpass:                                                   \
-       {                                                               \
-         auto_diagnostic_group d;                                              \
-         if (warning_at (PLOC, OPT, AR, parmnum, rname, QUALS))        \
-           inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype); \
-       }                                                               \
-        break;                                                           \
-      case ic_assign:                                                    \
-        warning_at (LOCATION, OPT, AS, QUALS);                           \
-        break;                                                           \
-      case ic_init:                                                      \
-        warning_at (LOCATION, OPT, IN, QUALS);                           \
-        break;                                                           \
-      case ic_return:                                                    \
-        warning_at (LOCATION, OPT, RE, QUALS);                           \
-        break;                                                           \
-      default:                                                           \
-        gcc_unreachable ();                                              \
-      }                                                                  \
-  } while (0)
+     compile time.  It is the same as PEDWARN_FOR_ASSIGNMENT but with an
+     extra parameter to enumerate qualifiers.  */
+#define PEDWARN_FOR_QUALIFIERS(LOCATION, PLOC, OPT, AR, AS, IN, RE, QUALS) \
+   WARNING_FOR_QUALIFIERS (true, LOCATION, PLOC, OPT, AR, AS, IN, RE, QUALS)
+
 
   if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR)
     rhs = TREE_OPERAND (rhs, 0);
@@ -7370,17 +7364,18 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
 
              if (TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttr)
                  & ~TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttl))
-               WARNING_FOR_QUALIFIERS (location, expr_loc,
-                                       OPT_Wdiscarded_array_qualifiers,
-                                       G_("passing argument %d of %qE discards "
+               WARNING_FOR_QUALIFIERS (flag_isoc2x,
+                                       location, expr_loc,
+                                       OPT_Wdiscarded_array_qualifiers,
+                                       G_("passing argument %d of %qE discards "
                                           "%qv qualifier from pointer target type"),
-                                       G_("assignment discards %qv qualifier "
+                                       G_("assignment discards %qv qualifier "
                                           "from pointer target type"),
-                                       G_("initialization discards %qv qualifier "
+                                       G_("initialization discards %qv qualifier "
                                           "from pointer target type"),
-                                       G_("return discards %qv qualifier from "
+                                       G_("return discards %qv qualifier from "
                                           "pointer target type"),
-                                        TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl));
+                                       TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl));
             }
           else if (pedantic
              && ((VOID_TYPE_P (ttl) && TREE_CODE (ttr) == FUNCTION_TYPE)
@@ -7403,28 +7398,31 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
          else if (TREE_CODE (ttr) != FUNCTION_TYPE
                   && TREE_CODE (ttl) != FUNCTION_TYPE)
            {
+              /* Assignments between atomic and non-atomic objects are OK.  */
+              bool warn_quals_ped = TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttr)
+                                    & ~TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttl);
+              bool warn_quals = TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttr)
+                                & ~TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (strip_array_types (ttl));
+
              /* Don't warn about loss of qualifier for conversions from
                 qualified void* to pointers to arrays with corresponding
-                qualifier on the element type. */
-             if (!pedantic)
-               ttl = strip_array_types (ttl);
+                qualifier on the element type (except for pedantic before C23). */
+             if (warn_quals || (warn_quals_ped && pedantic && !flag_isoc2x))
+               PEDWARN_FOR_QUALIFIERS (location, expr_loc,
+                                       OPT_Wdiscarded_qualifiers,
+                                       G_("passing argument %d of %qE discards "
+                                          "%qv qualifier from pointer target type"),
+                                       G_("assignment discards %qv qualifier "
+                                          "from pointer target type"),
+                                       G_("initialization discards %qv qualifier "
+                                          "from pointer target type"),
+                                       G_("return discards %qv qualifier from "
+                                          "pointer target type"),
+                                       TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl));
+             else if (warn_quals_ped)
+               pedwarn_c11 (location, OPT_Wc11_c2x_compat,
+                            "array with qualifier on the element is not qualified before C2X");
 
-             /* Assignments between atomic and non-atomic objects are OK.  */
-             if (TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttr)
-                 & ~TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttl))
-               {
-                 PEDWARN_FOR_QUALIFIERS (location, expr_loc,
-                                         OPT_Wdiscarded_qualifiers,
-                                         G_("passing argument %d of %qE discards "
-                                            "%qv qualifier from pointer target type"),
-                                         G_("assignment discards %qv qualifier "
-                                            "from pointer target type"),
-                                         G_("initialization discards %qv qualifier "
-                                            "from pointer target type"),
-                                         G_("return discards %qv qualifier from "
-                                            "pointer target type"),
-                                         TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl));
-               }
              /* If this is not a case of ignoring a mismatch in signedness,
                 no warning.  */
              else if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
diff --git a/gcc/testsuite/gcc.dg/c11-qual-1.c b/gcc/testsuite/gcc.dg/c11-qual-1.c
new file mode 100644 (file)
index 0000000..f731e06
--- /dev/null
@@ -0,0 +1,11 @@
+/* Test that qualifiers are lost in tertiary operator for pointers to arrays before C2X, PR98397 */
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -pedantic-errors -Wno-discarded-array-qualifiers" } */
+
+void foo(void)
+{
+       const int (*u)[1];
+       void *v;
+       _Static_assert(_Generic(1 ? u : v, const void*: 0, void*: 1), "qualifier not lost");
+       _Static_assert(_Generic(1 ? v : u, const void*: 0, void*: 1), "qualifier not lost");
+}
diff --git a/gcc/testsuite/gcc.dg/c2x-qual-1.c b/gcc/testsuite/gcc.dg/c2x-qual-1.c
new file mode 100644 (file)
index 0000000..4d33db1
--- /dev/null
@@ -0,0 +1,30 @@
+/* Tests related to qualifiers and pointers to arrays in C2X, PR98397 */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+/* test that qualifiers are preserved in tertiary operator for pointers to arrays in C2X */
+
+void f(void)
+{
+       const int (*u)[1];
+       void *v;
+       _Static_assert(_Generic(1 ? u : v, const void*: 1, void*: 0), "lost qualifier");
+       _Static_assert(_Generic(1 ? v : u, const void*: 1, void*: 0), "lost qualifier");
+}
+
+/* test that assignment of unqualified to qualified pointers works as expected */
+
+void g(void)
+{
+       int (*x)[3];
+       const int (*p)[3] = x;
+}
+
+/* test that assignment of qualified void pointers works as expected */
+
+void h(void)
+{
+       const void* x;
+       const int (*p)[3] = x;
+}
+
diff --git a/gcc/testsuite/gcc.dg/c2x-qual-2.c b/gcc/testsuite/gcc.dg/c2x-qual-2.c
new file mode 100644 (file)
index 0000000..f60a5b1
--- /dev/null
@@ -0,0 +1,30 @@
+/* Tests related to qualifiers and pointers to arrays in C2X, PR98397 */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -Wc11-c2x-compat" } */
+
+/* test that qualifiers are preserved in tertiary operator for pointers to arrays in C2X */
+
+void f(void)
+{
+       const int (*u)[1];
+       void *v;
+       _Static_assert(_Generic(1 ? u : v, const void*: 1, void*: 0), "lost qualifier");        /* { dg-warning "pointer to array loses qualifier in conditional" } */
+       _Static_assert(_Generic(1 ? v : u, const void*: 1, void*: 0), "lost qualifier");        /* { dg-warning "pointer to array loses qualifier in conditional" } */
+}
+
+/* test that assignment of unqualified to qualified pointers works as expected */
+
+void g(void)
+{
+       int (*x)[3];
+       const int (*p)[3] = x; /* { dg-warning "arrays with different qualifiers"  } */
+}
+
+/* test that assignment of qualified void pointers works as expected */
+
+void h(void)
+{
+       const void* x;
+       const int (*p)[3] = x; /* { dg-warning "array with qualifier on the element is not qualified before C2X" } */
+}
+
diff --git a/gcc/testsuite/gcc.dg/c2x-qual-3.c b/gcc/testsuite/gcc.dg/c2x-qual-3.c
new file mode 100644 (file)
index 0000000..31896fc
--- /dev/null
@@ -0,0 +1,30 @@
+/* Tests related to qualifiers and pointers to arrays in C2X, PR98397 */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -Wc11-c2x-compat -pedantic-errors" } */
+
+/* test that qualifiers are preserved in tertiary operator for pointers to arrays in C2X */
+
+void f(void)
+{
+       const int (*u)[1];
+       void *v;
+       _Static_assert(_Generic(1 ? u : v, const void*: 1, void*: 0), "lost qualifier");        /* { dg-warning "pointer to array loses qualifier in conditional" } */
+       _Static_assert(_Generic(1 ? v : u, const void*: 1, void*: 0), "lost qualifier");        /* { dg-warning "pointer to array loses qualifier in conditional" } */
+}
+
+/* test that assignment of unqualified to qualified pointers works as expected */
+
+void g(void)
+{
+       int (*x)[3];
+       const int (*p)[3] = x; /* { dg-warning "arrays with different qualifiers"  } */
+}
+
+/* test that assignment of qualified void pointers works as expected */
+
+void h(void)
+{
+       const void* x;
+       const int (*p)[3] = x; /* { dg-warning "array with qualifier on the element is not qualified before C2X" } */
+}
+
diff --git a/gcc/testsuite/gcc.dg/c2x-qual-4.c b/gcc/testsuite/gcc.dg/c2x-qual-4.c
new file mode 100644 (file)
index 0000000..93b4723
--- /dev/null
@@ -0,0 +1,105 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c2x" } */
+void tvoid(void* x);
+void transpose0(double* out, const double* in) { }
+void transpose1(double out[2][2], const double in[2][2]) { }
+void transpose2(double out[2][2][2], const double in[2][2][2]) { }
+// return
+int (*y2(const int x[3][3]))[3] { return x; } /* { dg-warning "return discards 'const' qualifier from pointer target type" } */
+const int (*y3(int x[3][3]))[3] { return x; }
+void test(void)
+{
+       double x0[2];
+       double y0[2];
+       const double z0[4];
+       double x1[2][2];
+       double y1[2][2];
+       double o1[2][3];
+       const double z1[2][2];
+       double x2[2][2][2];
+       double y2[2][2][2];
+       double o2[2][2][3];
+       const double z2[2][2][2];
+       // void pointers
+       tvoid(x0);
+       tvoid(x1);
+       tvoid(x2);
+       tvoid(z0); /* { dg-warning "passing argument 1 of 'tvoid' discards 'const' qualifier from pointer target type" } */
+       tvoid(z1); /* { dg-warning "passing argument 1 of 'tvoid' discards 'const' qualifier from pointer target type" } */
+       tvoid(z2); /* { dg-warning "passing argument 1 of 'tvoid' discards 'const' qualifier from pointer target type" } */
+       void* p;
+       const void* pc;
+       p = x0;
+       p = x1;
+       p = x2;
+       p = z0; /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+       p = z1; /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+       p = z2; /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+       pc = x0;
+       pc = x1;
+       pc = x2;
+       pc = z0;
+       pc = z1;
+       pc = z2;
+       transpose0(pc, p); /* { dg-warning "passing argument 1 of 'transpose0' discards 'const' qualifier from pointer target type" } */
+       transpose1(pc, p); /* { dg-warning "passing argument 1 of 'transpose1' discards 'const' qualifier from pointer target type" } */
+       transpose2(pc, p); /* { dg-warning "passing argument 1 of 'transpose2' discards 'const' qualifier from pointer target type" } */
+       transpose0(p, pc);
+       transpose1(p, pc);
+       transpose2(p, pc);
+       // passing as arguments
+       transpose0(y0, x0);
+       transpose1(y1, x1);
+       transpose2(y2, x2);
+       // initialization
+       const double (*u0p) = x0;
+       const double (*u1p)[2] = x1;
+       const double (*u2p)[2][2] = x2;
+       double (*v0p) = z0; /* { dg-warning "initialization discards 'const' qualifier from pointer target type" } */
+       double (*v1p)[2] = z1; /* { dg-warning "initialization discards 'const' qualifier from pointer target type" } */
+       double (*v2p)[2][2] = z2; /* { dg-warning "initialization discards 'const' qualifier from pointer target type" } */
+       // subtraction
+       &(x0[1]) - &(z0[0]);
+       &(x1[1]) - &(z1[0]);
+       &(x2[1]) - &(z2[0]);
+       // comparison
+       x0 == z0;
+       x1 == z1;
+       x2 == z2;
+       x0 < z0; 
+       x1 < z1; 
+       x2 < z2; 
+       x0 > z0;
+       x1 > z1;
+       x2 > z2;
+       // assignment
+       u0p = x0;
+       u1p = x1;
+       u2p = x2;
+       v0p = z0; /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+       v1p = z1; /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+       v2p = z2; /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+       // conditional expressions
+       (void)(1 ? x0 : z0);
+       (void)(1 ? x1 : z1);
+       (void)(1 ? x2 : z2);
+       (void)(1 ? x0 : x1); /* { dg-warning "pointer type mismatch in conditional expression" } */
+       (void)(1 ? x1 : x2); /* { dg-warning "pointer type mismatch in conditional expression" } */
+       (void)(1 ? x2 : x0); /* { dg-warning "pointer type mismatch in conditional expression" } */
+       v0p = (1 ? z0 : v0p); /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+       v1p = (1 ? z1 : v1p); /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+       v2p = (1 ? z2 : v2p); /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+       v0p = (1 ? x0 : u0p); /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+       v1p = (1 ? x1 : u1p); /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+       v2p = (1 ? x2 : u2p); /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+       (1 ? x0 : z0)[0] = 1; /* { dg-error "assignment of read-only location" } */
+       (1 ? x1 : z1)[0][0] = 1; /* { dg-error "assignment of read-only location" } */
+       (1 ? x2 : z2)[0][0][0] = 1; /* { dg-error "assignment of read-only location" } */
+       v0p = (1 ? p : z0); /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+       v1p = (1 ? p : z1); /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+       v2p = (1 ? p : z2); /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+       v0p = (1 ? pc : x0); /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+       v1p = (1 ? pc : x1); /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+       v2p = (1 ? pc : x2); /* { dg-warning "assignment discards 'const' qualifier from pointer target type" } */
+}
+
diff --git a/gcc/testsuite/gcc.dg/c2x-qual-5.c b/gcc/testsuite/gcc.dg/c2x-qual-5.c
new file mode 100644 (file)
index 0000000..0801fa0
--- /dev/null
@@ -0,0 +1,101 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+void tvoid(void* x);
+void transpose0(double* out, const double* in) { }
+void transpose1(double out[2][2], const double in[2][2]) { }
+void transpose2(double out[2][2][2], const double in[2][2][2]) { }
+// return
+int (*x2(const int x[3][3]))[3] { return x; } /* { dg-error "return discards" } */
+const int (*x3(int x[3][3]))[3] { return x; }
+void test(void)
+{
+       double x0[2];
+       double y0[2];
+       const double z0[4];
+       double x1[2][2];
+       double y1[2][2];
+       double o1[2][3];
+       const double z1[2][2];
+       double x2[2][2][2];
+       double y2[2][2][2];
+       double o2[2][2][3];
+       const double z2[2][2][2];
+       // void pointers
+       tvoid(z0); /* { dg-error "passing argument 1 of 'tvoid' discards 'const' qualifier from pointer target type" } */
+       tvoid(z1); /* { dg-error "passing argument 1 of 'tvoid' discards 'const' qualifier from pointer target type" } */
+       tvoid(z2); /* { dg-error "passing argument 1 of 'tvoid' discards 'const' qualifier from pointer target type" } */
+       void* p;
+       const void* pc;
+       p = x0;
+       p = x1;
+       p = x2;
+       p = z0; /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+       p = z1; /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+       p = z2; /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+       pc = x0;
+       pc = x1;
+       pc = x2;
+       pc = z0;
+       pc = z1;
+       pc = z2;
+       transpose0(pc, p); /* { dg-error "passing argument 1 of 'transpose0' discards 'const' qualifier from pointer target type" } */
+       transpose1(pc, p); /* { dg-error "passing argument 1 of 'transpose1' discards 'const' qualifier from pointer target type" } */
+       transpose2(pc, p); /* { dg-error "passing argument 1 of 'transpose2' discards 'const' qualifier from pointer target type" } */
+       transpose0(p, pc);
+       transpose1(p, pc);
+       transpose2(p, pc);
+       // passing as arguments
+       transpose0(y0, x0);
+       transpose1(y1, o1); /* { dg-error "passing argument 2 of 'transpose1' from incompatible pointer type" } */
+       transpose1(y1, x1);
+       transpose2(y2, o2); /* { dg-error "passing argument 2 of 'transpose2' from incompatible pointer type" } */
+       transpose2(y2, x2);
+       // initialization
+       const double (*x0p) = x0;
+       const double (*x1p)[2] = x1;
+       const double (*x2p)[2][2] = x2;
+       double (*v0p) = z0; /* { dg-error "initialization discards 'const' qualifier from pointer target type" } */
+       double (*v1p)[2] = z1; /* { dg-error "initialization discards" } */
+       double (*v2p)[2][2] = z2; /* { dg-error "initialization discards" } */
+       // assignment
+       x0p = x0;
+       x1p = x1;
+       x2p = x2;
+       // subtraction
+       &(x0[1]) - &(z0[0]);
+       &(x1[1]) - &(z1[0]);
+       &(x2[1]) - &(z2[0]);
+       // comparison
+       x0 == z0;
+       x1 == z1;
+       x2 == z2;
+       x0 < z0;
+       x1 < z1;
+       x2 < z2;
+       x0 > z0;
+       x1 > z1;
+       x2 > z2;
+       // conditional expressions
+       (void)(1 ? x0 : z0);
+       (void)(1 ? x1 : z1);
+       (void)(1 ? x2 : z2);
+       (void)(1 ? x0 : x1); /* { dg-error "pointer type mismatch in conditional expression" } */
+       (void)(1 ? x1 : x2); /* { dg-error "pointer type mismatch in conditional expression" } */
+       (void)(1 ? x2 : x0); /* { dg-error "pointer type mismatch in conditional expression" } */
+       v0p = (1 ? z0 : v0p); /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+       v1p = (1 ? z1 : v1p); /* { dg-error "assignment discards" } */
+       v2p = (1 ? z2 : v2p); /* { dg-error "assignment discards" } */
+       v0p = (1 ? x0 : x0p); /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+       v1p = (1 ? x1 : x1p); /* { dg-error "assignment discards" } */
+       v2p = (1 ? x2 : x2p); /* { dg-error "assignment discards" } */
+       (1 ? x0 : z0)[0] = 1; /* { dg-error "assignment of read-only location" } */
+       (1 ? x1 : z1)[0][0] = 1; /* { dg-error "assignment of read-only location" } */
+       (1 ? x2 : z2)[0][0][0] = 1; /* { dg-error "assignment of read-only location" } */
+       v0p = (1 ? p : z0); /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+       v1p = (1 ? p : z1); /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+       v2p = (1 ? p : z2); /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+       v0p = (1 ? pc : x0); /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+       v1p = (1 ? pc : x1); /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+       v2p = (1 ? pc : x2); /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+}
+
diff --git a/gcc/testsuite/gcc.dg/c2x-qual-6.c b/gcc/testsuite/gcc.dg/c2x-qual-6.c
new file mode 100644 (file)
index 0000000..9c91e20
--- /dev/null
@@ -0,0 +1,114 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -Wc11-c2x-compat -pedantic-errors" } */
+void tvoid(void* x);
+void transpose0(double* out, const double* in) { }
+void transpose1(double out[2][2], const double in[2][2]) { }
+void transpose2(double out[2][2][2], const double in[2][2][2]) { }
+// return
+int (*x2(const int x[3][3]))[3] { return x; } /* { dg-warning "before C2X" } */
+                                               /* { dg-error "return discards" "" { target *-*-* } .-1 } */
+const int (*x3(int x[3][3]))[3] { return x; }  /* { dg-warning "before C2X" } */
+void test(void)
+{
+       double x0[2];
+       double y0[2];
+       const double z0[4];
+       double x1[2][2];
+       double y1[2][2];
+       double o1[2][3];
+       const double z1[2][2];
+       double x2[2][2][2];
+       double y2[2][2][2];
+       double o2[2][2][3];
+       const double z2[2][2][2];
+       // void pointers
+       tvoid(z0); /* { dg-error "passing argument 1 of 'tvoid' discards 'const' qualifier from pointer target type" } */
+       tvoid(z1); /* { dg-error "passing argument 1 of 'tvoid' discards 'const' qualifier from pointer target type" } */
+       tvoid(z2); /* { dg-error "passing argument 1 of 'tvoid' discards 'const' qualifier from pointer target type" } */
+       void* p;
+       const void* pc;
+       p = x0;
+       p = x1;
+       p = x2;
+       p = z0; /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+       p = z1; /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+       p = z2; /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+       pc = x0;
+       pc = x1;
+       pc = x2;
+       pc = z0;
+       pc = z1;
+       pc = z2;
+       transpose0(pc, p); /* { dg-error "passing argument 1 of 'transpose0' discards 'const' qualifier from pointer target type" } */
+       transpose1(pc, p); /* { dg-error "passing argument 1 of 'transpose1' discards 'const' qualifier from pointer target type" } */
+       transpose2(pc, p); /* { dg-error "passing argument 1 of 'transpose2' discards 'const' qualifier from pointer target type" } */
+       transpose0(p, pc); 
+       transpose1(p, pc); /* { dg-warning "before C2X" } */
+       transpose2(p, pc); /* { dg-warning "before C2X" } */
+       // passing as arguments
+       transpose0(y0, x0);
+       transpose1(y1, o1); /* { dg-error "passing argument 2 of 'transpose1' from incompatible pointer type" } */
+       transpose1(y1, x1); /* { dg-warning "before C2X" } */
+       transpose2(y2, o2); /* { dg-error "passing argument 2 of 'transpose2' from incompatible pointer type" } */
+       transpose2(y2, x2); /* { dg-warning "before C2X" } */
+       // initialization
+       const double (*x0p) = x0;
+       const double (*x1p)[2] = x1; /* { dg-warning "before C2X" } */
+       const double (*x2p)[2][2] = x2; /* { dg-warning "before C2X" } */
+       double (*v0p) = z0; /* { dg-error "initialization discards 'const' qualifier from pointer target type" } */
+       double (*v1p)[2] = z1; /* { dg-warning "before C2X" } */
+                               /* { dg-error "initialization discards" "" { target *-*-* } .-1 } */
+       double (*v2p)[2][2] = z2; /* { dg-warning "before C2X" } */
+                               /* { dg-error "initialization discards" "" { target *-*-* } .-1 } */
+                               
+       // assignment
+       x0p = x0;
+       x1p = x1; /* { dg-warning "before C2X" } */
+       x2p = x2; /* { dg-warning "before C2X" } */
+
+       // subtraction
+       &(x0[1]) - &(z0[0]);
+       &(x1[1]) - &(z1[0]); /* { dg-warning "before C2X" } */
+       &(x2[1]) - &(z2[0]); /* { dg-warning "before C2X" } */
+       // comparison
+       x0 == z0;
+       x1 == z1; /* { dg-warning "before C2X" } */
+       x2 == z2; /* { dg-warning "before C2X" } */
+       x0 < z0;
+       x1 < z1; /* { dg-warning "before C2X" } */
+       x2 < z2; /* { dg-warning "before C2X" } */
+       x0 > z0;
+       x1 > z1; /* { dg-warning "before C2X" } */
+       x2 > z2; /* { dg-warning "before C2X" } */
+       // conditional expressions
+       (void)(1 ? x0 : z0);
+       (void)(1 ? x1 : z1); /* { dg-warning "before C2X" } */
+       (void)(1 ? x2 : z2); /* { dg-warning "before C2X" } */
+       (void)(1 ? x0 : x1); /* { dg-error "pointer type mismatch in conditional expression" } */
+       (void)(1 ? x1 : x2); /* { dg-error "pointer type mismatch in conditional expression" } */
+       (void)(1 ? x2 : x0); /* { dg-error "pointer type mismatch in conditional expression" } */
+       v0p = (1 ? z0 : v0p); /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+       v1p = (1 ? z1 : v1p); /* { dg-warning "before C2X" } */
+                               /* { dg-error "assignment discards" "" { target *-*-* } .-1 } */
+       v2p = (1 ? z2 : v2p); /* { dg-warning "before C2X" } */
+                               /* { dg-error "assignment discards" "" { target *-*-* } .-1 } */
+       v0p = (1 ? x0 : x0p); /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+       v1p = (1 ? x1 : x1p); /* { dg-error "assignment discards" } */
+                               /* { dg-warning "before C2X" "" { target *-*-* } .-1 } */
+       v2p = (1 ? x2 : x2p); /* { dg-error "assignment discards" } */
+                               /* { dg-warning "before C2X" "" { target *-*-* } .-1 } */
+       (1 ? x0 : z0)[0] = 1; /* { dg-error "assignment of read-only location" } */
+       (1 ? x1 : z1)[0][0] = 1; /* { dg-error "assignment of read-only location" } */
+                               /* { dg-warning "before C2X" "" { target *-*-* } .-1 } */
+       (1 ? x2 : z2)[0][0][0] = 1; /* { dg-error "assignment of read-only location" } */
+                               /* { dg-warning "before C2X" "" { target *-*-* } .-1 } */
+       v0p = (1 ? p : z0); /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+       v1p = (1 ? p : z1); /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+                               /* { dg-warning "before C2X" "" { target *-*-* } .-1 } */
+       v2p = (1 ? p : z2); /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+                               /* { dg-warning "before C2X" "" { target *-*-* } .-1 } */
+       v0p = (1 ? pc : x0); /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+       v1p = (1 ? pc : x1); /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+       v2p = (1 ? pc : x2); /* { dg-error "assignment discards 'const' qualifier from pointer target type" } */
+}
+
diff --git a/gcc/testsuite/gcc.dg/c2x-qual-7.c b/gcc/testsuite/gcc.dg/c2x-qual-7.c
new file mode 100644 (file)
index 0000000..5fe15e1
--- /dev/null
@@ -0,0 +1,16 @@
+/* Tests related to qualifiers and pointers to arrays in C2X, PR98397 */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+/* test that _Atomic qualifier is not preserved in tertiary operator for pointers to arrays in C2X */
+
+void f(void)
+{
+       _Atomic void *u;
+       void *v;
+       _Static_assert(_Generic(1 ? u : v, _Atomic void*: 0, void*: 1), "_Atomic should be removed");
+       _Static_assert(_Generic(1 ? v : u, _Atomic void*: 0, void*: 1), "_Atomic should be removed");
+}
+
+
+
index 921a37e9e0d5b32104c1fa8b73d11ad54c6f927f..498ab223162711d0c2f19292d2743af9a5272908 100644 (file)
@@ -1,6 +1,6 @@
 /* { dg-do compile } */
 /* Origin: Martin Uecker <uecker@eecs.berkeley.edu> */
-/* { dg-options "-Wdiscarded-array-qualifiers" } */
+/* { dg-options "" } */
 void tvoid(void* x);
 void transpose0(double* out, const double* in) { }
 void transpose1(double out[2][2], const double in[2][2]) { }
index 30689c7312d56715d8d5115230ae91a1494d40d9..4c95d8a3a7858059074927069a2283b06ff2c87c 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-Wdiscarded-array-qualifiers -pedantic-errors" } */
+/* { dg-options "-pedantic-errors" } */
 /* Origin: Martin Uecker <uecker@eecs.berkeley.edu> */
 void tvoid(void* x);
 void transpose0(double* out, const double* in) { }